From 1ffe1a9a7c5199e46bf280806456a5d86f314169 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Thu, 23 Oct 2014 09:50:57 +0200 Subject: [PATCH 001/323] Allow hostname from lock files to be empty The common format for lock files is to only contain the PID. (See http://www.pathname.com/fhs/2.2/fhs-5.9.html) Qt includes some extra information but we can not expect this information to be present. Otherwise lock files created by other (non-Qt) processes are not handled correctly. Change-Id: Ib9be3c9f07eb8e87193f56d96f5559bbdd5180b8 Reviewed-by: David Faure --- src/corelib/io/qlockfile.cpp | 2 +- src/corelib/io/qlockfile_unix.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp index 18a782a8f3..c256507430 100644 --- a/src/corelib/io/qlockfile.cpp +++ b/src/corelib/io/qlockfile.cpp @@ -287,7 +287,7 @@ bool QLockFilePrivate::getLockInfo(qint64 *pid, QString *hostname, QString *appn appNameLine.chop(1); QByteArray hostNameLine = reader.readLine(); hostNameLine.chop(1); - if (pidLine.isEmpty() || appNameLine.isEmpty()) + if (pidLine.isEmpty()) return false; qint64 thePid = pidLine.toLongLong(); diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 2fe93f0af6..3ed973494b 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -183,7 +183,7 @@ bool QLockFilePrivate::isApparentlyStale() const QString hostname, appname; if (!getLockInfo(&pid, &hostname, &appname)) return false; - if (hostname == QString::fromLocal8Bit(localHostName())) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { if (::kill(pid, 0) == -1 && errno == ESRCH) return true; // PID doesn't exist anymore } From 5bfe794aaab34d6aa021b5640972509e3bc6ced8 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 16 Oct 2014 15:12:59 +0200 Subject: [PATCH 002/323] Remove trailing '\n' in qFormatLogMessage output Do not automatically add a \n to all messages formatted by qFormatLogMessage. Some backends require a final newline, some don't, so it's best to only append it where it's actually needed. The returned string will be null if the pattern is empty. This allows to differentiate between the case that the pattern just didn't apply (empty line is printed), and the case that qSetMessagePattern(QString()) have been called (nothing is printed). Change-Id: I17fde997a4074f58f82de6dea129948155c322d6 Reviewed-by: Oswald Buddenhagen Reviewed-by: Alex Blasche --- src/corelib/global/qlogging.cpp | 19 +++++++++---------- src/testlib/qtestlog.cpp | 1 - .../corelib/global/qlogging/tst_qlogging.cpp | 12 ++++++------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index f356bab42d..6def794d5e 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1101,14 +1101,9 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con if (!pattern) { // after destruction of static QMessagePattern instance message.append(str); - message.append(QLatin1Char('\n')); return message; } - // don't print anything if pattern was empty - if (pattern->tokens[0] == 0) - return message; - bool skip = false; // we do not convert file, function, line literals to local encoding due to overhead @@ -1227,7 +1222,6 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con message.append(QLatin1String(token)); } } - message.append(QLatin1Char('\n')); return message; } @@ -1289,7 +1283,7 @@ static void android_default_message_handler(QtMsgType type, case QtFatalMsg: priority = ANDROID_LOG_FATAL; break; }; - __android_log_print(priority, "Qt", "%s:%d (%s): %s", + __android_log_print(priority, "Qt", "%s:%d (%s): %s\n", context.file, context.line, context.function, qPrintable(message)); } @@ -1303,16 +1297,21 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con { QString logMessage = qFormatLogMessage(type, context, buf); + // print nothing if message pattern didn't apply / was empty. + // (still print empty lines, e.g. because message itself was empty) + if (logMessage.isNull()) + return; + if (!qt_logging_to_console()) { #if defined(Q_OS_WIN) + logMessage.append(QLatin1Char('\n')); OutputDebugString(reinterpret_cast(logMessage.utf16())); return; #elif defined(QT_USE_SLOG2) + logMessage.append(QLatin1Char('\n')); slog2_default_handler(type, logMessage.toLocal8Bit().constData()); return; #elif defined(QT_USE_JOURNALD) && !defined(QT_BOOTSTRAPPED) - // remove trailing \n, systemd appears to want them newline-less - logMessage.chop(1); systemd_default_message_handler(type, context, logMessage); return; #elif defined(Q_OS_ANDROID) @@ -1320,7 +1319,7 @@ static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &con return; #endif } - fprintf(stderr, "%s", logMessage.toLocal8Bit().constData()); + fprintf(stderr, "%s\n", logMessage.toLocal8Bit().constData()); fflush(stderr); } diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 7ea953232f..e48fdc1ad0 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -279,7 +279,6 @@ namespace QTest { return; QString msg = qFormatLogMessage(type, context, message); - msg.chop(1); // remove trailing newline if (type != QtFatalMsg) { if (counter.load() <= 0) diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 35bd518b3a..0a55da5b7e 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -886,25 +886,25 @@ void tst_qmessagehandler::formatLogMessage_data() #define BA QByteArrayLiteral QTest::newRow("basic") << "%{type} %{file} %{line} %{function} %{message}" - << "debug main.cpp 1 func msg\n" + << "debug main.cpp 1 func msg" << QtDebugMsg << BA("main.cpp") << 1 << BA("func") << BA("") << "msg"; // test the if conditions QString format = "[%{if-debug}D%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{if-category}%{category}: %{endif}%{message}"; QTest::newRow("if-debug") - << format << "[D] msg\n" + << format << "[D] msg" << QtDebugMsg << BA("") << 0 << BA("func") << QByteArray() << "msg"; QTest::newRow("if_warning") - << format << "[W] msg\n" + << format << "[W] msg" << QtWarningMsg << BA("") << 0 << BA("func") << QByteArray() << "msg"; QTest::newRow("if_critical") - << format << "[C] msg\n" + << format << "[C] msg" << QtCriticalMsg << BA("") << 0 << BA("func") << QByteArray() << "msg"; QTest::newRow("if_fatal") - << format << "[F] msg\n" + << format << "[F] msg" << QtFatalMsg << BA("") << 0 << BA("func") << QByteArray() << "msg"; QTest::newRow("if_cat") - << format << "[F] cat: msg\n" + << format << "[F] cat: msg" << QtFatalMsg << BA("") << 0 << BA("func") << BA("cat") << "msg"; } From 631a55ccf48f2a128d03a4d2554a8154dfd2f7ee Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Tue, 21 Oct 2014 11:02:26 +0200 Subject: [PATCH 003/323] QStorageInfo: include qt_windows.h instead of Windows.h This fixes a compilation issue with X-MinGW builds and is more appropriate here. Change-Id: Id97e387c6e22a2c09d2f4dda35ce1bed2831fffe Reviewed-by: Kai Koehne --- src/corelib/io/qstorageinfo_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp index b0d3e7c6da..8c276b2798 100644 --- a/src/corelib/io/qstorageinfo_win.cpp +++ b/src/corelib/io/qstorageinfo_win.cpp @@ -45,7 +45,7 @@ #include #include -#include +#include QT_BEGIN_NAMESPACE From 309e82021de1b49753559086592749d9fe02b239 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Fri, 24 Oct 2014 14:09:41 +0400 Subject: [PATCH 004/323] Doc: Include QtWidgets instead of QtGui Change-Id: Ib7f3183efd446abb7cc191f33128b4e230ee372c Reviewed-by: Jerome Pasion --- examples/widgets/doc/src/application.qdoc | 6 +++--- examples/widgets/doc/src/dockwidgets.qdoc | 4 ++-- src/widgets/doc/snippets/code/doc_src_layout.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/widgets/doc/src/application.qdoc b/examples/widgets/doc/src/application.qdoc index 0d244bce00..e0379e9d75 100644 --- a/examples/widgets/doc/src/application.qdoc +++ b/examples/widgets/doc/src/application.qdoc @@ -75,12 +75,12 @@ \snippet mainwindows/application/mainwindow.cpp 0 - We start by including \c , a header file that contains the - definition of all classes in the Qt Core and Qt GUI + We start by including \c , a header file that contains the + definition of all classes in the Qt Core, Qt GUI and Qt Widgets modules. This saves us from the trouble of having to include every class individually. We also include \c mainwindow.h. - You might wonder why we don't include \c in \c + You might wonder why we don't include \c in \c mainwindow.h and be done with it. The reason is that including such a large header from another header file can rapidly degrade performances. Here, it wouldn't do any harm, but it's still diff --git a/examples/widgets/doc/src/dockwidgets.qdoc b/examples/widgets/doc/src/dockwidgets.qdoc index 2987ec1211..a11524f4f4 100644 --- a/examples/widgets/doc/src/dockwidgets.qdoc +++ b/examples/widgets/doc/src/dockwidgets.qdoc @@ -55,8 +55,8 @@ \snippet mainwindows/dockwidgets/mainwindow.cpp 0 - We start by including \c , a header file that contains the - definition of all classes in the Qt Core and Qt GUI + We start by including \c , a header file that contains the + definition of all classes in the Qt Core, Qt GUI and Qt Widgets modules. This saves us from having to include every class individually and is especially convenient if we add new widgets. We also include \c mainwindow.h. diff --git a/src/widgets/doc/snippets/code/doc_src_layout.cpp b/src/widgets/doc/snippets/code/doc_src_layout.cpp index 5ea8ce5a5f..a10cd52e2e 100644 --- a/src/widgets/doc/snippets/code/doc_src_layout.cpp +++ b/src/widgets/doc/snippets/code/doc_src_layout.cpp @@ -42,7 +42,7 @@ #ifndef CARD_H #define CARD_H -#include +#include #include class CardLayout : public QLayout From c803af51677c31ec7010f5c481ad59272694f138 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 22 Oct 2014 18:06:36 +0200 Subject: [PATCH 005/323] fix crash when dropping a file into an empty QTextEdit Since commit be0bfe09ee4b99e9ab45c6898949b5d144e77a29 we return -1 in QTextEngine::findItem if the item cannot be found. Calling code must be prepared for this case. Otherwise we run into an out-of-bounds vector access later on. Task-number: QTBUG-42103 Change-Id: Ie338cd1fc3cf0ce1e8edfa59dead635669020a33 Reviewed-by: Konstantin Ritt --- src/gui/text/qtextlayout.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index adc5663299..911d1b8bc7 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2559,6 +2559,10 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const } else itm = eng->findItem(pos); + if (itm < 0) { + *cursorPos = 0; + return x.toReal(); + } eng->shapeLine(line); const QScriptItem *si = &eng->layoutData->items[itm]; From bd94a46f619395032ef48b2a53db294488738532 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 22 Oct 2014 12:03:33 +0200 Subject: [PATCH 006/323] QSettings: Fix handling of long long ints with CFPreferences back-end. The CFNumberGetValue() function does not work as advertised: For some (but not all) CFNumbers containing a long long value outside the range of int, it returns true when asked to convert to an int, so the wrong value is extracted from the CFNumber. As a workaround, use CFNumberGetType() to find out whether the value is actually an int. Task-number: QTBUG-42017 Change-Id: Ib95395491d0db61d2bdc0f058a6a2f6be05da432 Reviewed-by: Thiago Macieira Reviewed-by: Eike Ziller --- src/corelib/io/qsettings_mac.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp index 4752077f87..344bec0309 100644 --- a/src/corelib/io/qsettings_mac.cpp +++ b/src/corelib/io/qsettings_mac.cpp @@ -235,8 +235,10 @@ static QVariant qtValue(CFPropertyListRef cfvalue) int i; qint64 ll; - if (CFNumberGetValue(cfnumber, kCFNumberIntType, &i)) + if (CFNumberGetType(cfnumber) == kCFNumberIntType) { + CFNumberGetValue(cfnumber, kCFNumberIntType, &i); return i; + } CFNumberGetValue(cfnumber, kCFNumberLongLongType, &ll); return ll; } From 2d0b251b1d3059970ca7cf221cfa8e64c9a021e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 23 Oct 2014 15:17:27 +0200 Subject: [PATCH 007/323] Cocoa: Expose on window size change only Don't send expose events on window move. Task-number: QTBUG-42126 Change-Id: I6e758f9037a2a785c651b63d25b53e7a009b1fdf Reviewed-by: Laszlo Agocs --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 3366e5bc3c..60c772702c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1811,7 +1811,7 @@ void QCocoaWindow::updateExposedGeometry() if (!isWindowExposable()) return; - if (m_exposedGeometry == geometry() && m_exposedDevicePixelRatio == devicePixelRatio()) + if (m_exposedGeometry.size() == geometry().size() && m_exposedDevicePixelRatio == devicePixelRatio()) return; m_isExposed = true; From be8f647364ad2d995ff3b370710a35c83e760806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sun, 26 Oct 2014 21:48:08 +0100 Subject: [PATCH 008/323] Send screen change events before expose events. This fixes the "expose event received for window with invalid geometry" warning from Qt Quick. The window's current screen is now up to date when processing the expose event. Change-Id: Ia5c83e34154182699ec587835f9063809d819d7d Reviewed-by: Laszlo Agocs --- src/plugins/platforms/cocoa/qnsview.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index ca98f6cec3..b33f71fd46 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -437,9 +437,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (m_window) { NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen]; if (screenIndex != NSNotFound) { - m_platformWindow->updateExposedGeometry(); QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex); QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen()); + m_platformWindow->updateExposedGeometry(); } } } else { From 9157087334186ff3ef811f2ec234a3bf5d4a4889 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Fri, 24 Oct 2014 15:54:28 +0200 Subject: [PATCH 009/323] Rotate images according to Exif orientation Task-number: QTBUG-37946 Change-Id: I181f88acdff0ef76aa02e968dc6afca1ed495f38 Reviewed-by: aavit --- src/gui/image/qjpeghandler.cpp | 150 +++++++++++++++++- .../images/jpeg_exif_orientation_value_1.jpg | Bin 0 -> 910 bytes .../images/jpeg_exif_orientation_value_2.jpg | Bin 0 -> 910 bytes .../images/jpeg_exif_orientation_value_3.jpg | Bin 0 -> 988 bytes .../images/jpeg_exif_orientation_value_4.jpg | Bin 0 -> 995 bytes .../images/jpeg_exif_orientation_value_5.jpg | Bin 0 -> 912 bytes .../images/jpeg_exif_orientation_value_6.jpg | Bin 0 -> 911 bytes .../images/jpeg_exif_orientation_value_7.jpg | Bin 0 -> 987 bytes .../images/jpeg_exif_orientation_value_8.jpg | Bin 0 -> 991 bytes tests/auto/gui/image/qimage/tst_qimage.cpp | 18 +++ 10 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_6.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg create mode 100644 tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 481101db93..7ca8969798 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -726,7 +726,7 @@ public: }; QJpegHandlerPrivate(QJpegHandler *qq) - : quality(75), iod_src(0), state(Ready), q(qq) + : quality(75), exifOrientation(1), iod_src(0), state(Ready), q(qq) {} ~QJpegHandlerPrivate() @@ -741,8 +741,10 @@ public: bool readJpegHeader(QIODevice*); bool read(QImage *image); + void applyExifOrientation(QImage *image); int quality; + int exifOrientation; QVariant size; QImage::Format format; QSize scaledSize; @@ -760,6 +762,97 @@ public: QJpegHandler *q; }; +static bool readExifHeader(QDataStream &stream) +{ + char prefix[6]; + if (stream.readRawData(prefix, sizeof(prefix)) != sizeof(prefix)) + return false; + if (prefix[0] != 'E' || prefix[1] != 'x' || prefix[2] != 'i' || prefix[3] != 'f' || prefix[4] != 0 || prefix[5] != 0) + return false; + return true; +} + +/* + * Returns -1 on error + * Returns 0 if no Exif orientation was found + * Returns 1 orientation is horizontal (normal) + * Returns 2 mirror horizontal + * Returns 3 rotate 180 + * Returns 4 mirror vertical + * Returns 5 mirror horizontal and rotate 270 CCW + * Returns 6 rotate 90 CW + * Returns 7 mirror horizontal and rotate 90 CW + * Returns 8 rotate 270 CW + */ +static int getExifOrientation(QByteArray &exifData) +{ + QDataStream stream(&exifData, QIODevice::ReadOnly); + + if (!readExifHeader(stream)) + return -1; + + quint16 val; + quint32 offset; + + // read byte order marker + stream >> val; + if (val == 0x4949) // 'II' == Intel + stream.setByteOrder(QDataStream::LittleEndian); + else if (val == 0x4d4d) // 'MM' == Motorola + stream.setByteOrder(QDataStream::BigEndian); + else + return -1; // unknown byte order + + // read size + stream >> val; + if (val != 0x2a) + return -1; + + stream >> offset; + // we have already used 8 bytes of TIFF header + offset -= 8; + + // read IFD + while (!stream.atEnd()) { + quint16 numEntries; + + // skip offset bytes to get the next IFD + if (stream.skipRawData(offset) != (qint32)offset) + return -1; + + stream >> numEntries; + + for (;numEntries > 0; --numEntries) { + quint16 tag; + quint16 type; + quint32 components; + quint32 value; + + stream >> tag >> type >> components >> value; + + if (tag == 0x0112) { // Tag Exif.Image.Orientation + if (components !=1) + return -1; + if (type != 3) // we are expecting it to be an unsigned short + return -1; + if (value < 1 || value > 8) // check for valid range + return -1; + + // It is possible to include the orientation multiple times. + // Right now the first value is returned. + return value; + } + } + + // read offset to next IFD + stream >> offset; + if (offset == 0) // this is the last IFD + break; + } + + // No Exif orientation was found + return 0; +} /*! \internal */ @@ -779,6 +872,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) if (!setjmp(err.setjmp_buffer)) { jpeg_save_markers(&info, JPEG_COM, 0xFFFF); + jpeg_save_markers(&info, JPEG_APP0+1, 0xFFFF); // Exif uses APP1 marker (void) jpeg_read_header(&info, TRUE); @@ -790,6 +884,8 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) format = QImage::Format_Invalid; read_jpeg_format(format, &info); + QByteArray exifData; + for (jpeg_saved_marker_ptr marker = info.marker_list; marker != NULL; marker = marker->next) { if (marker->marker == JPEG_COM) { QString key, value; @@ -807,9 +903,18 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) description += key + QLatin1String(": ") + value.simplified(); readTexts.append(key); readTexts.append(value); + } else if (marker->marker == JPEG_APP0+1) { + exifData.append((const char*)marker->data, marker->data_length); } } + if (exifData.size()) { + // Exif data present + int orientation = getExifOrientation(exifData); + if (orientation > 0) + exifOrientation = orientation; + } + state = ReadHeader; return true; } @@ -823,6 +928,48 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device) return true; } +void QJpegHandlerPrivate::applyExifOrientation(QImage *image) +{ + // This is not an optimized implementation, but easiest to maintain + QTransform transform; + + switch (exifOrientation) { + case 1: // normal + break; + case 2: // mirror horizontal + *image = image->mirrored(true, false); + break; + case 3: // rotate 180 + transform.rotate(180); + *image = image->transformed(transform); + break; + case 4: // mirror vertical + *image = image->mirrored(false, true); + break; + case 5: // mirror horizontal and rotate 270 CCW + *image = image->mirrored(true, false); + transform.rotate(270); + *image = image->transformed(transform); + break; + case 6: // rotate 90 CW + transform.rotate(90); + *image = image->transformed(transform); + break; + case 7: // mirror horizontal and rotate 90 CW + *image = image->mirrored(true, false); + transform.rotate(90); + *image = image->transformed(transform); + break; + case 8: // rotate 270 CW + transform.rotate(-90); + *image = image->transformed(transform); + break; + default: + qWarning("This should never happen"); + } + exifOrientation = 1; +} + bool QJpegHandlerPrivate::read(QImage *image) { if(state == Ready) @@ -834,6 +981,7 @@ bool QJpegHandlerPrivate::read(QImage *image) if (success) { for (int i = 0; i < readTexts.size()-1; i+=2) image->setText(readTexts.at(i), readTexts.at(i+1)); + applyExifOrientation(image); state = Ready; return true; diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aaa4ac4e10f40e6a32560aef43b553e804f0a973 GIT binary patch literal 910 zcmex=@c%Z0 zGe`$T0AvV727omGKg1x&!NA49#mp$kz$D1XEXer(2!j~dJ0O?B06POGP+XFcfr%O9 z5d>gkVrF6ee~Wz(=SUhmhk>$zLYFZ;^Qy*Xp@!!9$`S)MazOgeKTC9?CS%G6(;wklud z*8?q*2U*0x$bzs5=n+PC239sf0U<@OWlSK;7+4uJ9kip4IA${*U~Ndh;=oeN(b1R2 z@hmMZea)X&em+k+RA)(4vY%7x(!8uvc=GAoUzsV>O1si$WnQk(s=Tm(RaJ{IYMK&* zlJd;YAP)k=0~~Ac5CH`s8>4^_G(_0!nZoV6S4G?jw>(++tL*7>F_y&N`@^?SQH?Px zl-_b%H1pZ#&oLcUcHVbpv`%p-4Y|*15}D6^JUlf&*Yvu-ao4ZRrO$k8MQk?;$9y;G z?9JxrZF5PBo4)V&ccArRpy)sajPSUyR}{TIo!P$icWIex`Wm+NuekhyjsnLlSeHNv zKhOwKL0|--0H_I|$Pw^faBSzpY#Eny2S?MYosLecR)a!Y45$ZH6C(q}T2LSh*vWgX zm{6$Bz$E=-){a-n<}c5K>=8iI!oa8i4I`kI;#YER*`^&=LApid+04N35 AMF0Q* literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a61d2723d7cf43ee9244f4dcb6b26d848574a480 GIT binary patch literal 910 zcmex=>Y?(AtXBkCs161k%1ZL zPh`N##>Ddf76T76BLkBFvjEVym*4elSJ@emF31klAua&21z7_dGm8LF0|zL)SedF# zo@*8=m&VTrs#O#On$Ez$$_iJ`$i%|Tz{SEB3f?O;B>8U}nWRec5HX`RX%{8Fcm}D@-|a=DWw4GgFtixb9vO zy&D9+-v?PK0JH-oNSIleSlJi_grR}LX3uoocJk)8ewn#!;^x^-oatBB@TSf?)zrl7 zwq{3lG+Wgvv1RM$h+KPmeR-_QEeGED?}TP9+ho}mnX<&1N3Lzfam%xI6P6iztmz1v zGHJ>Q&(oXd{J!bE_kAtUb}>+NAbbmCF*3ko!(NeDxnkYrBt{Ww$9lsm#Z{+bfNlcE zEI5b+82Eukhzp{}C@|$f%mBrW0B0$Sj0ocb1qP?Yea_K6W=6T^>Veusf!a_kW?+P9 z0tK>w+XE(xbM9d$y!aVjFdmu1nGe(->>Kn<)5C;n#;;;xvy%_1)O>qVvO I_5W`I093Zmxc~qF literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..43e56dcef70bbd6cf48fae727ea5f6cb4d63061e GIT binary patch literal 988 zcmex=>Y?(AtWa|2T)uB=t*Xf zM-YI8jf3<5Ee0N-Fp~hY0MNI=ya{gaK05#Dyz!p_s7G7?WDi0E0|N^iI|EP)2Pni? znJ#WoK4ZOk%hH{Hw{D%81J)uZ2(pEV8KI4liG>-ci&arT5Udj@WzYDhx7%IYQ0J@} z&l&$O(=0VrCV!b!H>qy&^T^Wa(f6DK>kir#p|#jj3gK zy;7L%uzKm~!`{gmWj7*cnVIRWTTvbpA8#_7L+2i!-j)>(W+%^1=el~Uy0!2a-|gOy zcTW47oXjhWO!?6%^2VU()=|SV(Gjhhx=8}lw!Y8Ya_0BC(74^pBU5+PKG54?zSW6= z!D=m!BS+g+H${%pwQN>lnqDqp8wKTn&J+d4CURT?<68h0m-dPi7AGB-R@YSu-L(G7 z!tf8QzyK4hQhfD`AE*SJLclpdpg|v$E(C#Ljbaod15)e?EZZ$GZ@s37h}Po(jj2I>+ML`zJ-dJtOEO@}jAme#}38+Ox0L{e=3UC(-NEPw4 c<;{yOihgMQw`8jpNA32x_o^1S*!{l=0P;Kok^lez literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5d06f740922c4ecd4e49cd2aaa90a8293c4e108 GIT binary patch literal 995 zcmex={xcvIrKfhkD{O+;sc9na`y3^XP=J1+^ zhsyBqEt-{4!gl?_x0zedWloklq-><5dw)OBei?8;Az9A=w4RBTjX^{V8dhxfOn>4w zuWr=sOP-uABzfuS=Qi2t+pJq|uXSF&dj5s%jq5FcM4r-YYkQ+}mH7+1*}9u;wI@w3 zcAeJwETNv*Jn5O`xtygO!4gYm3oO;t&7LrQ%f0V2w=PSoy{k68^u~%=bNhWZb?IKt zWlWvMc6kxg>ju9ojts6*Jx;ROj+eGB)fVmOuLn9*Q~(h~kO*QFfW@Z0qTAz1j~bVG zIf)1RADP!twQtI=eA@!k`hsAf5^y460L7|611N2X2_kzJWELX>#3)ew3LHA;UEO0e zS@+P{2ZnKdKv`D2dO-0baAe^FJq8)i1JnGzZrO4=+3W;JivZY8kohnmUZda0FylhIRF3v literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1886f3775e047d42bb5ffb2af704f84434af336b GIT binary patch literal 912 zcmex=>Y?(AtXBoCs16Rk%1ZH z4+LOhW?}n(i-89y%p|}p0QBq?f!eYRncJt1cdQ2LkQ88GLe;{;4io|D;Q)mgE7Q8Q zyt`)XR+$|B8K_)Z5M%+e21X_pW&uG(L$C&BMn-$ab-UKDn!RpWciy(%)tgRzyVSLM zRj+iG=CayGz_tXO| zk^@`B#Ka8u3eYEvZ0rJptU`)lyO=aUf)`s*e4lK1C9ersW&(hM; z*Zlc-bCWlF$~PW^vo?XQ=PY9;9#;yt+2n10?%vF2vr0NNg%>(-d4(`-)p22PaW_5= zv{nWZ90*$(m|2)u*%%oFgrFh9X3w;B>G^KeIY)!NO0VYKeEc?k{-F|yc0s8P;rX+< zGp)|Po5&!wZJ%bycU2P!#i%SB{u$vi32%4Yvo<=NyD4(+v`AYmS8E=bO%r{J#ex*Q zJiSupEVVqn>3#KUpaaAN7?3Ond!A7M78&-6O?8vx5+BOv?%nkHI%D{ER(_xqIBvnZ z1RnH*j1UB-8+fpR7(nNPjQ~ZDfcK03osW}J0%reBNVi!M5VC6Ze7u@K;VfV$@3mq= yp*ql(!jjB_8)ts$1NDdspxMK~r~r4WK=ivr$7{z#%~w>Y?(AtXBoCs16Rk%1ZH z4+LOhVP*S&i-89y%p|}p0QBtTXKedox}W7<(R^eN)FL4O)PkyqnT?4BsD}d-VysL@ zU#n}Ln7)6N2~e?|Ajo`1R)l&+CKhIPRyF}eLqV_>pjq~ep&^U`46E!#!!Iz@gvv88 zUtqrQ@#H3Nc9kL?gR?e)uJ``lR4F{!SA1G!^Vip(=4CEF8myy!SjA`Kag~@)XF~;@ z8f@x;wn>3(0|F%9FtaeS3P5aP0@<`~*ZNhn*RAT#-PRtSI(6ri(9n<#b6rg?JTlwY zzUAz?VvifwBqb*b=KVaHxV`^mw$F@X#R|z1hb|i%PjyL4i(ca5x_e3VZV>o>9%!Si z00R@ygGgb>%)-RV#>gNbC=3k|HhZScC-?SU(4DpN7ngL*J@M4^2&tpRKZ>p{vIq!> zT5vvc!`5pnIj_%jeR=(KBip3EvpG*cb6wUG7MX77beKnGvf;VnP%Wn!N7YlDrfi)DJX5To5(TfJO*H%>c!Y0P|iA8HR>O3=T{M_EY?R_qLo228Fg5NE;%kk!%Kq zv_Sq5;TMOML%SxmH|$_2RA-6-Y7r4Y)xf}@0C%c@Xw1nQUHpf8_MBRAbn6F&tM&hH F0sz;@-NOI? literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b3dcc466a907a504db72fa83957326bfcc5aac78 GIT binary patch literal 987 zcmex=>Y?(AtXB|7f@V+k%1ZL zPh`Nt#=-gj76T76BLkBFvjEVyD;s9!tyXc4ynVj56{tsC0AvrU7Ip@p77kE|u`*rQ zlI|mGd9UWm*R5M;=KN;>YLOEJTEoDEWECS53o{!#1FNEdAXq0*%AWD#;@-}*X=!OH zo6RJ}RQ{?=+JDLOm*+44=aHq;qwin)TU&a!_K@zjdxA%`H=X*ieBq*1uNGf8xK-q` z+XcJb7x%6E^>*93TiJ_^cZ;d~1llSKvK7UHOw25dtPE`IP)nIWmVWYI_E(KFtxbNx z?<0Y(Rw;d!w(EDBZ1T1`YJAq@5i^R)_rJ90KM_j6b?i2+^Cvs$hk~b_e?G-1i=`)tpd?Tr{Uo zx|O;?Ip_tt&|u52V|C-?FNFmU_!wk74=@3BhzOu*U{HX&S3v5KAy>Lm Z^@`#H;nhnfX))AppL?%rfs5V$n*d6*1>67t literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg b/tests/auto/gui/image/qimage/images/jpeg_exif_orientation_value_8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bc390e2b9a7e8704f824eaedf0248a2181b6650 GIT binary patch literal 991 zcmex=w%gi1sIrsvPgi1oq?H+6{w2? z6lknWiBi`e^Vg|MgnsNelE88Rs7Fo^Xb}Sw6Ej>FBNGcV13Q}{tAHR_BhVf8j8Epy zylLQVV(?9Tj;l!UW0k^_PwTC1HhJ4+_k8xX3ttxD-{vthxzB6o(^;#OS{Z61Q@dlm zwq9DbC2!U0eG5a~dKehYA23ugR58y7S}F^+6lgHqu}sV?j6e@EK<#7#+4*yhKHp`t z?VXP$jtLs}qzKKNIq#+9%t>21I<}W|mxDn4{&}g-;_~Zf|NMHr^1H{j+g0u%>rQLG zn!{@v9xB7bw`f*I3ETAx-)3$-mpNJLkg}1I?*08B`yl~^6jng%nONBv1cb$)fyHLe zR36>^=hz{Kc+VL}(kI`jPEkJh^lQoCsBQBL=UctW{v!DzamBJSQK=|%r{hO&J=>V( zb2(i_@% literal 0 HcmV?d00001 diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 5f581c9d0f..fcee2884d9 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -173,6 +173,8 @@ private slots: void invertPixelsRGB_data(); void invertPixelsRGB(); + void exifOrientation(); + void cleanupFunctions(); private: @@ -2624,6 +2626,22 @@ void tst_QImage::invertPixelsRGB() QCOMPARE(qBlue(pixel) >> 4, (255 - 96) >> 4); } +void tst_QImage::exifOrientation() +{ + for (unsigned int i = 1; i <= 8; ++i) { + QImage img; + QRgb px; + + QVERIFY(img.load(m_prefix + QString::fromLatin1("jpeg_exif_orientation_value_%1.jpg").arg(i))); + + px = img.pixel(0, 0); + QVERIFY(qRed(px) > 250 && qGreen(px) < 5 && qBlue(px) < 5); + + px = img.pixel(img.width() - 1, 0); + QVERIFY(qRed(px) < 5 && qGreen(px) < 5 && qBlue(px) > 250); + } +} + static void cleanupFunction(void* info) { bool *called = static_cast(info); From 4d84c25157b18b29cd2a42714e3b352674d28486 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sun, 26 Oct 2014 22:26:25 +0100 Subject: [PATCH 010/323] Don't link to Xlib's Xrender library We don't use this library in XCB plugin. Change-Id: Ifcc2f404b3cbf5601eb094eaac923d2f9e6e981b Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/xcb-plugin.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 9aaafadcad..f14fcde73f 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -60,7 +60,7 @@ contains(QT_CONFIG, xcb-xlib) { # to support custom cursors with depth > 1 contains(QT_CONFIG, xcb-render) { DEFINES += XCB_USE_RENDER - LIBS += -lxcb-render -lxcb-render-util -lXrender + LIBS += -lxcb-render -lxcb-render-util } # build with session management support From ac4bab991b0b258853611dd2b5662dc111fa6311 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 22 Oct 2014 10:30:46 +0200 Subject: [PATCH 011/323] QSwipeGestureRecognizer: Prevent cancel in startup-phase. Replace the boolean 'started' member by an enumeration which indicates the startup phase. While in that phase, do not cancel when pressed points are detected for fewer than 3 touch points. Task-number: QTBUG-15768 Change-Id: Ic57b19e3002392fb632f551f615d80ada9831d34 Reviewed-by: Shawn Rutledge --- src/widgets/kernel/qgesture_p.h | 10 ++++++++-- src/widgets/kernel/qstandardgestures.cpp | 23 +++++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/widgets/kernel/qgesture_p.h b/src/widgets/kernel/qgesture_p.h index 8668145d8a..183a2eba0f 100644 --- a/src/widgets/kernel/qgesture_p.h +++ b/src/widgets/kernel/qgesture_p.h @@ -134,11 +134,17 @@ class QSwipeGesturePrivate : public QGesturePrivate Q_DECLARE_PUBLIC(QSwipeGesture) public: + enum State { + NoGesture, + Started, + ThreePointsReached + }; + QSwipeGesturePrivate() : horizontalDirection(QSwipeGesture::NoDirection), verticalDirection(QSwipeGesture::NoDirection), swipeAngle(0), - started(false), velocityValue(0) + state(NoGesture), velocityValue(0) { } @@ -150,7 +156,7 @@ public: qreal swipeAngle; QPoint lastPositions[3]; - bool started; + State state; qreal velocityValue; QElapsedTimer time; }; diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index 0822c04033..9e3cb473e5 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -283,7 +283,7 @@ QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state, case QEvent::TouchBegin: { d->velocityValue = 1; d->time.start(); - d->started = true; + d->state = QSwipeGesturePrivate::Started; result = QGestureRecognizer::MayBeGesture; break; } @@ -297,9 +297,10 @@ QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state, } case QEvent::TouchUpdate: { const QTouchEvent *ev = static_cast(event); - if (!d->started) + if (d->state == QSwipeGesturePrivate::NoGesture) result = QGestureRecognizer::CancelGesture; else if (ev->touchPoints().size() == 3) { + d->state = QSwipeGesturePrivate::ThreePointsReached; QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2); @@ -354,12 +355,18 @@ QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state, } else if (ev->touchPoints().size() > 3) { result = QGestureRecognizer::CancelGesture; } else { // less than 3 touch points - if (d->started && (ev->touchPointStates() & Qt::TouchPointPressed)) - result = QGestureRecognizer::CancelGesture; - else if (d->started) - result = QGestureRecognizer::Ignore; - else + switch (d->state) { + case QSwipeGesturePrivate::NoGesture: result = QGestureRecognizer::MayBeGesture; + break; + case QSwipeGesturePrivate::Started: + result = QGestureRecognizer::Ignore; + break; + case QSwipeGesturePrivate::ThreePointsReached: + result = (ev->touchPointStates() & Qt::TouchPointPressed) + ? QGestureRecognizer::CancelGesture : QGestureRecognizer::Ignore; + break; + } } break; } @@ -378,7 +385,7 @@ void QSwipeGestureRecognizer::reset(QGesture *state) d->swipeAngle = 0; d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint(); - d->started = false; + d->state = QSwipeGesturePrivate::NoGesture; d->velocityValue = 0; d->time.invalidate(); From 10800a3b4ccf9a57e73dd2e9e0e674d7ff3c2b1b Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 13 Oct 2014 10:22:22 +0200 Subject: [PATCH 012/323] Doc: Corrected autolink errors qtbase Task-number: QTBUG-40362 Change-Id: I054a4713bdd83280be51697689e0c3c3409b9601 Reviewed-by: Mitch Curtis --- src/corelib/animation/qvariantanimation.cpp | 8 ++++---- src/corelib/global/qlogging.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index dcbf55f28b..f47dec6ce0 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE There are two ways to affect how QVariantAnimation interpolates the values. You can set an easing curve by calling setEasingCurve(), and configure the duration by calling - setDuration(). You can change how the QVariants are interpolated + setDuration(). You can change how the \l{QVariant}s are interpolated by creating a subclass of QVariantAnimation, and reimplementing the virtual interpolated() function. @@ -110,7 +110,7 @@ QT_BEGIN_NAMESPACE If you need to interpolate other variant types, including custom types, you have to implement interpolation for these yourself. To do this, you can register an interpolator function for a given - type. This function takes 3 parameters: the start value, the end value + type. This function takes 3 parameters: the start value, the end value, and the current progress. Example: @@ -378,8 +378,8 @@ QVariantAnimation::~QVariantAnimation() keyValues are referring to this effective progress. The easing curve is used with the interpolator, the interpolated() - virtual function, the animation's duration, and iterationCount, to - control how the current value changes as the animation progresses. + virtual function, and the animation's duration to control how the + current value changes as the animation progresses. */ QEasingCurve QVariantAnimation::easingCurve() const { diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 6def794d5e..9fced6ede6 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1578,7 +1578,7 @@ void qErrnoWarning(int code, const char *msg, ...) The default \a pattern is "%{if-category}%{category}: %{endif}%{message}". The \a pattern can also be changed at runtime by setting the QT_MESSAGE_PATTERN - environment variable; if both qSetMessagePattern() is called and QT_MESSAGE_PATTERN is + environment variable; if both \l qSetMessagePattern() is called and QT_MESSAGE_PATTERN is set, the environment variable takes precedence. Custom message handlers can use qFormatLogMessage() to take \a pattern into account. From 366faaafff72600994ea5aae7c212888c2a23b5e Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 23 Oct 2014 15:21:49 +0200 Subject: [PATCH 013/323] Doc: Corrected identifiers for QByteArray::toBase64 in snippet Task-number: QTBUG-40944 Change-Id: I31fc23739b3e145b3668b10fdf4465c19d2fdb01 Reviewed-by: Martin Smith --- .../doc/snippets/code/src_corelib_tools_qbytearray.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp index 9210d2737f..97be131203 100644 --- a/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_tools_qbytearray.cpp @@ -354,10 +354,10 @@ text.toBase64(); // returns "UXQgaXMgZ3JlYXQh" //! [39bis] QByteArray text("

Hello?

"); -text.toBase64(QByteArray::Base64 | QByteArray::OmitTrailingEquals); // returns "PHA+SGVsbG8/PC9wPg" -text.toBase64(QByteArray::Base64); // returns "PHA+SGVsbG8/PC9wPg==" -text.toBase64(QByteArray::Base64Url); // returns "PHA-SGVsbG8_PC9wPg==" -text.toBase64(QByteArray::Base64Url | QByteArray::OmitTrailingEquals); // returns "PHA-SGVsbG8_PC9wPg" +text.toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals); // returns "PHA+SGVsbG8/PC9wPg" +text.toBase64(QByteArray::Base64Encoding); // returns "PHA+SGVsbG8/PC9wPg==" +text.toBase64(QByteArray::Base64UrlEncoding); // returns "PHA-SGVsbG8_PC9wPg==" +text.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); // returns "PHA-SGVsbG8_PC9wPg" //! [39bis] From cc1435952d796476616f54319c1ddf57eeaf80f7 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 17 Oct 2014 15:56:05 +0200 Subject: [PATCH 014/323] Doc: link to MIBenum Task-number: QTBUG- 40362 Change-Id: I0261117d8aef8383ef77887a201d61ed0bd0ba52 Reviewed-by: Mitch Curtis --- src/corelib/codecs/qtextcodec.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 9d13e1b892..24cb4e7038 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -441,7 +441,7 @@ QTextCodec::ConverterState::~ConverterState() an empty list. For example, "ISO-8859-1" has "latin1", "CP819", "IBM819", and "iso-ir-100" as aliases. - \row \li mibEnum() + \row \li \l{QTextCodec::mibEnum()}{mibEnum()} \li Return the MIB enum for the encoding if it is listed in the \l{IANA character-sets encoding file}. @@ -704,7 +704,7 @@ QTextCodec* QTextCodec::codecForLocale() \fn int QTextCodec::mibEnum() const Subclasses of QTextCodec must reimplement this function. It - returns the MIBenum (see \l{IANA character-sets encoding file} + returns the \l{QTextCodec::mibEnum()}{MIBenum} (see \l{IANA character-sets encoding file} for more information). It is important that each QTextCodec subclass returns the correct unique value for this function. */ @@ -733,7 +733,7 @@ QList QTextCodec::aliases() const \a state can be 0, in which case the conversion is stateless and default conversion rules should be used. If state is not 0, the codec should save the state after the conversion in \a state, and - adjust the remainingChars and invalidChars members of the struct. + adjust the \c remainingChars and \c invalidChars members of the struct. */ /*! @@ -749,7 +749,7 @@ QList QTextCodec::aliases() const \a state can be 0 in which case the conversion is stateless and default conversion rules should be used. If state is not 0, the codec should save the state after the conversion in \a state, and - adjust the remainingChars and invalidChars members of the struct. + adjust the \c remainingChars and \c invalidChars members of the struct. */ /*! From 2b666d9576210aa98700e219dba6b1bd4f93d793 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 23 Oct 2014 14:45:18 +0200 Subject: [PATCH 015/323] Fix shortcut handling with non-latin layouts Shortcut handling with non-latin keyboard layouts were broken for checks like: QKeyEvent key = ...; key == QKeySequence::SelectAll In Qt4 this was handled transparently when getting keysym from XLookupString. When ctrl modifier was set, XLookupString performed "keysym transformation" to obtain a latin keysym. Still this did not solve the non-latin shortcut issues for all cases due to some of Xlib assumptions which could not be controled by user. This patch implements XLookupString-like behavior in lookupLatinKeysym(). It is not a 1-to-1 copy of how XLookupString perfoms latin keysym lookup, but it serves our needs just fine. lookupLatinKeysym() also handles the cases that did not work in Qt4 with XLookupString, thanks to libxkbcommon keymap query API. And lookupLatinKeysym() replaces the fragile implementation of "fallback latin key" code path in possibleKeys(). Done-with: Ruslan Nigmatullin Task-number: QTBUG-33182 Task-number: QTBUG-32274 Change-Id: I56a5b624487ca6c2c3768220301a37dac39b439a Reviewed-by: Ruslan Nigmatullin Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 190 +++++++++++++++------ src/plugins/platforms/xcb/qxcbkeyboard.h | 5 + 2 files changed, 147 insertions(+), 48 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index dae3a79628..260fb46309 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -721,7 +721,7 @@ void QXcbKeyboard::updateKeymap() if (xkb_keymap) { new_state = xkb_state_new(xkb_keymap); } else { - printKeymapError("Failed to compile a keymap!"); + printKeymapError("Qt: Failed to compile a keymap!"); m_config = false; return; } @@ -737,6 +737,8 @@ void QXcbKeyboard::updateKeymap() xkb_state = new_state; if (!connection()->hasXKB()) updateXKBMods(); + + checkForLatinLayout(); } #ifndef QT_NO_XKB @@ -824,37 +826,137 @@ void QXcbKeyboard::updateXKBMods() xkb_mods.mod5 = xkb_keymap_mod_get_index(xkb_keymap, "Mod5"); } +static bool isLatin(xkb_keysym_t sym) +{ + return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z')); +} + +void QXcbKeyboard::checkForLatinLayout() +{ + m_hasLatinLayout = false; + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts(xkb_keymap); + const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; + const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) { + xkb_state_update_mask(kb_state, 0, 0, 0, 0, 0, layout); + for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, code); + // if layout can produce any of these latin letters (chosen + // arbitrarily) then it must be a latin key based layout + if (sym == XK_q || sym == XK_a || sym == XK_e) { + m_hasLatinLayout = true; + xkb_state_unref(kb_state); + return; + } + } + } + xkb_state_unref(kb_state); +} + +xkb_keysym_t QXcbKeyboard::lookupLatinKeysym(xkb_keycode_t keycode) const +{ + xkb_layout_index_t layout; + xkb_keysym_t sym = XKB_KEY_NoSymbol; + const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(xkb_keymap, keycode); + const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(xkb_state, keycode); + // Look at user layouts in the order in which they are defined in system + // settings to find a latin keysym. + for (layout = 0; layout < layoutCount; ++layout) { + if (layout == currentLayout) + continue; + const xkb_keysym_t *syms; + xkb_level_index_t level = xkb_state_key_get_level(xkb_state, keycode, layout); + if (xkb_keymap_key_get_syms_by_level(xkb_keymap, keycode, layout, level, &syms) != 1) + continue; + if (isLatin(syms[0])) { + sym = syms[0]; + break; + } + } + // If user layouts don't contain any layout that results in a latin key, we query a + // key from "US" layout, this allows for latin-key-based shorcuts to work even when + // users have only one (non-latin) layout set. + xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); + xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + if (sym == XKB_KEY_NoSymbol && !m_hasLatinLayout) { + if (!latin_keymap) { + const struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 }; + latin_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0); + static bool printFailure = true; + if (!latin_keymap && printFailure) { + // print message about failure to compile US keymap only once, + // no need to do this on every key press. + printFailure = false; + printKeymapError("Qt: Failed to compile US keymap, shortcut handling with " + "non-Latin keyboard layouts may not be fully functional!"); + } + } + if (latin_keymap) { + struct xkb_state *latin_state = xkb_state_new(latin_keymap); + if (latin_state) { + xkb_state_update_mask(latin_state, 0, latchedMods, lockedMods, 0, 0, 0); + sym = xkb_state_key_get_one_sym(latin_state, keycode); + xkb_state_unref(latin_state); + } else { + qWarning("QXcbKeyboard: failed to create a state for US keymap!"); + } + } + } + if (sym == XKB_KEY_NoSymbol) + return sym; + // Check for uniqueness, consider the following setup: + // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active). + // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+, + // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained + // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired + // then the obtained key is not unique. This prevents ctrl+ from generating a ctrl+q + // shortcut in the above described setup. We don't want ctrl+ and ctrl+ to + // generate the same shortcut event in this case. + const xcb_keycode_t minKeycode = connection()->setup()->min_keycode; + const xcb_keycode_t maxKeycode = connection()->setup()->max_keycode; + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); + for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) { + xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, prevLayout); + for (xcb_keycode_t code = minKeycode; code < maxKeycode; ++code) { + xkb_keysym_t prevSym = xkb_state_key_get_one_sym(kb_state, code); + if (prevSym == sym) { + sym = XKB_KEY_NoSymbol; + break; + } + } + } + xkb_state_unref(kb_state); + return sym; +} + QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const { // turn off the modifier bits which doesn't participate in shortcuts Qt::KeyboardModifiers notNeeded = Qt::MetaModifier | Qt::KeypadModifier | Qt::GroupSwitchModifier; Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; // create a fresh kb state and test against the relevant modifier combinations - // NOTE: it should be possible to query the keymap directly, once it gets - // supported by libxkbcommon - struct xkb_state * kb_state = xkb_state_new(xkb_keymap); + struct xkb_state *kb_state = xkb_state_new(xkb_keymap); if (!kb_state) { - qWarning("QXcbKeyboard: failed to compile xkb keymap"); + qWarning("QXcbKeyboard: failed to compile xkb keymap!"); return QList(); } // get kb state from the master xkb_state and update the temporary kb_state - xkb_layout_index_t baseLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_DEPRESSED); - xkb_layout_index_t latchedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LATCHED); xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LOCKED); xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); - xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, - baseLayout, latchedLayout, lockedLayout); + xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, 0, 0, lockedLayout); - xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); + quint32 keycode = event->nativeScanCode(); + xkb_keysym_t sym = xkb_state_key_get_one_sym(kb_state, keycode); if (sym == XKB_KEY_NoSymbol) { xkb_state_unref(kb_state); return QList(); } QList result; - int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, event->nativeScanCode())); + int baseQtKey = keysymToQtKey(sym, modifiers, lookupString(kb_state, keycode)); result += (baseQtKey + modifiers); // The base key is _always_ valid, of course xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); @@ -866,48 +968,33 @@ QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const Q_ASSERT(controlMod < 32); xkb_mod_mask_t depressed; - struct xkb_keymap *fallback_keymap = 0; int qtKey = 0; - //obtain a list of possible shortcuts for the given key event + // obtain a list of possible shortcuts for the given key event for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { Qt::KeyboardModifiers neededMods = ModsTbl[i]; if ((modifiers & neededMods) == neededMods) { - - depressed = 0; - if (neededMods & Qt::AltModifier) - depressed |= (1 << altMod); - if (neededMods & Qt::ShiftModifier) - depressed |= (1 << shiftMod); - if (neededMods & Qt::ControlModifier) - depressed |= (1 << controlMod); - - // update a keyboard state from a set of explicit masks if (i == 8) { - // Add a fall back key for layouts with non Latin-1 characters - if (baseQtKey > 255) { - struct xkb_rule_names names = { xkb_names.rules, xkb_names.model, "us", 0, 0 }; - fallback_keymap = xkb_keymap_new_from_names(xkb_context, &names, (xkb_keymap_compile_flags)0); - if (!fallback_keymap) - continue; - xkb_state_unref(kb_state); - kb_state = xkb_state_new(fallback_keymap); - if (!kb_state) - continue; - } else + if (isLatin(baseQtKey)) continue; + // add a latin key as a fall back key + sym = lookupLatinKeysym(keycode); } else { - xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, - baseLayout, latchedLayout, lockedLayout); + depressed = 0; + if (neededMods & Qt::AltModifier) + depressed |= (1 << altMod); + if (neededMods & Qt::ShiftModifier) + depressed |= (1 << shiftMod); + if (neededMods & Qt::ControlModifier) + depressed |= (1 << controlMod); + xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, 0, 0, lockedLayout); + sym = xkb_state_key_get_one_sym(kb_state, keycode); } - sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); - if (sym == XKB_KEY_NoSymbol) continue; Qt::KeyboardModifiers mods = modifiers & ~neededMods; - qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, event->nativeScanCode())); - - if (qtKey == baseQtKey || qtKey == 0) + qtKey = keysymToQtKey(sym, mods, lookupString(kb_state, keycode)); + if (!qtKey || qtKey == baseQtKey) continue; // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, @@ -926,8 +1013,6 @@ QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const } } xkb_state_unref(kb_state); - xkb_keymap_unref(fallback_keymap); - return result; } @@ -1002,6 +1087,8 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) , xkb_context(0) , xkb_keymap(0) , xkb_state(0) + , latin_keymap(0) + , m_hasLatinLayout(false) { memset(&xkb_names, 0, sizeof(xkb_names)); #ifndef QT_NO_XKB @@ -1029,6 +1116,7 @@ QXcbKeyboard::~QXcbKeyboard() xkb_state_unref(xkb_state); xkb_keymap_unref(xkb_keymap); xkb_context_unref(xkb_context); + xkb_keymap_unref(latin_keymap); if (!connection()->hasXKB()) xcb_key_symbols_free(m_key_symbols); clearXKBConfig(); @@ -1324,7 +1412,6 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, if (type == QEvent::KeyPress) targetWindow->updateNetWmUserTime(time); - // It is crucial the order of xkb_state_key_get_one_sym & xkb_state_update_key operations is not reversed! xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code); QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); @@ -1348,15 +1435,22 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, return; } - Qt::KeyboardModifiers modifiers = translateModifiers(state); - QString string = lookupString(xkb_state, code); int count = string.size(); string.truncate(count); - int qtcode = keysymToQtKey(sym, modifiers, string); - bool isAutoRepeat = false; + // Ιf control modifier is set we should prefer latin character, this is + // used for standard shortcuts in checks like "key == QKeySequence::Copy", + // users can still see the actual X11 keysym with QKeyEvent::nativeVirtualKey + Qt::KeyboardModifiers modifiers = translateModifiers(state); + xcb_keysym_t translatedSym = XKB_KEY_NoSymbol; + if (modifiers & Qt::ControlModifier && !isLatin(sym)) + translatedSym = lookupLatinKeysym(code); + if (translatedSym == XKB_KEY_NoSymbol) + translatedSym = sym; + int qtcode = keysymToQtKey(translatedSym, modifiers, string); + bool isAutoRepeat = false; if (type == QEvent::KeyPress) { if (m_autorepeat_code == code) { isAutoRepeat = true; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index e71165d824..9f1cf165cb 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -91,6 +91,9 @@ protected: void updateVModMapping(); void updateVModToRModMapping(); + xkb_keysym_t lookupLatinKeysym(xkb_keycode_t keycode) const; + void checkForLatinLayout(); + private: bool m_config; xcb_keycode_t m_autorepeat_code; @@ -99,6 +102,7 @@ private: struct xkb_keymap *xkb_keymap; struct xkb_state *xkb_state; struct xkb_rule_names xkb_names; + mutable struct xkb_keymap *latin_keymap; struct _mod_masks { uint alt; @@ -128,6 +132,7 @@ private: _mod_masks vmod_masks; int core_device_id; #endif + bool m_hasLatinLayout; }; QT_END_NAMESPACE From cd996c1b85313e89e781f5bd02e5aeae98b69d73 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 16 Oct 2014 17:40:23 +0200 Subject: [PATCH 016/323] QGtkStyle: fix segfault after re-creating QApp QGtkStylePrivate::setupGtkWidget() cannot use a local static variable for the container, but it must insert it to the GTK widget map together with all other GTK widgets. The container is destructed as a GtkWindow child in the Qt post routine QGtkStylePrivate::destroyWidgetMap(). Task-number: QTBUG-41145 Change-Id: If1fda372ed1227edc779fa4951cbd6fbf6038499 Reviewed-by: Andy Shaw Reviewed-by: Dmitry Shachnev Reviewed-by: Jens Bache-Wiig Reviewed-by: Shawn Rutledge --- src/widgets/styles/qgtkstyle_p.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qgtkstyle_p.cpp b/src/widgets/styles/qgtkstyle_p.cpp index 06ee74bdfe..61d1cd796e 100644 --- a/src/widgets/styles/qgtkstyle_p.cpp +++ b/src/widgets/styles/qgtkstyle_p.cpp @@ -701,10 +701,12 @@ GtkWidget* QGtkStylePrivate::getTextColorWidget() const void QGtkStylePrivate::setupGtkWidget(GtkWidget* widget) { if (Q_GTK_IS_WIDGET(widget)) { - static GtkWidget* protoLayout = 0; + GtkWidget *protoLayout = gtkWidgetMap()->value("GtkContainer"); if (!protoLayout) { protoLayout = QGtkStylePrivate::gtk_fixed_new(); QGtkStylePrivate::gtk_container_add((GtkContainer*)(gtkWidgetMap()->value("GtkWindow")), protoLayout); + QHashableLatin1Literal widgetPath = QHashableLatin1Literal::fromData(strdup("GtkContainer")); + gtkWidgetMap()->insert(widgetPath, protoLayout); } Q_ASSERT(protoLayout); From 0db6230cf603926c297362c7d483d27eee4fd01a Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Mon, 27 Oct 2014 14:55:08 +0100 Subject: [PATCH 017/323] ANGLE: Delete the ShaderImpl on gl::Shader object destruction. Cherry-picked from https://chromium-review.googlesource.com/224106 Task-number: QTBUG-41588 Change-Id: I27d75da76cec0b3341f549a3e6891c1c6d321358 Reviewed-by: Andrew Knight --- src/3rdparty/angle/src/libGLESv2/Shader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp index e3da2b1a9e..4cf5251ff9 100644 --- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp @@ -37,6 +37,7 @@ Shader::Shader(ResourceManager *manager, rx::ShaderImpl *impl, GLenum type, GLui Shader::~Shader() { + SafeDelete(mShader); } GLuint Shader::getHandle() const From 3777618fce31f5e12d019218cd5d95d9623b6136 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 17 Oct 2014 14:32:21 +0200 Subject: [PATCH 018/323] QMacStyle: Refactor painter offset into drawNSViewInRect() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I05067ee400f0b776b0f0418ee1c5fbd45126c29e Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 75 +++++++++++++------------- src/widgets/styles/qmacstyle_mac_p_p.h | 4 +- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index d909e13f9a..366de2ff9f 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1830,7 +1830,7 @@ static QCocoaWidget cocoaWidgetFromHIThemeButtonKind(ThemeButtonKind kind) return w; } -NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget, QPoint *offset) const +NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const { NSView *bv = cocoaControls[widget]; if (!bv) { @@ -1903,35 +1903,36 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget, QPoint *offset) cons const_cast(this)->cocoaControls.insert(widget, bv); } - if (offset) { - if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeLarge)) - offset->setY(2); - else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeSmall)) - *offset = QPoint(-1, 2); - else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeMini)) - offset->setY(2); - else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeSmall) - || widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeLarge)) - offset->setY(1); - else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeSmall)) - offset->setX(-1); - else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeMini)) - *offset = QPoint(7, 5); - else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeMini)) - *offset = QPoint(2, -1); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeLarge)) - *offset = QPoint(3, -1); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeSmall)) - *offset = QPoint(2, 1); - else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeMini)) - *offset = QPoint(5, 0); - } - return bv; } -void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRect &qtRect, QPainter *p, QCocoaDrawRectBlock drawRectBlock) const +void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, QCocoaDrawRectBlock drawRectBlock) const { + QPoint offset; + if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeLarge)) + offset.setY(2); + else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeSmall)) + offset = QPoint(-1, 2); + else if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeMini)) + offset.setY(2); + else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeSmall) + || widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeLarge)) + offset.setY(1); + else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeSmall)) + offset.setX(-1); + else if (widget == QCocoaWidget(QCocoaCheckBox, QAquaSizeMini)) + offset = QPoint(7, 5); + else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeMini)) + offset = QPoint(2, -1); + else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeLarge)) + offset = QPoint(3, -1); + else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeSmall)) + offset = QPoint(2, 1); + else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeMini)) + offset = QPoint(5, 0); + + p->translate(offset); + QMacCGContext ctx(p); CGContextSaveGState(ctx); @@ -1951,6 +1952,8 @@ void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRect &qtRect, QPain [NSGraphicsContext restoreGraphicsState]; CGContextRestoreGState(ctx); + + p->translate(-offset); } void QMacStylePrivate::resolveCurrentNSView(QWindow *window) @@ -2046,8 +2049,8 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD } pm = QPixmap::fromImage(image); } else if ((usingYosemiteOrLater && combo && !editableCombo) || button) { - QPoint offset; - NSButton *bc = (NSButton *)cocoaControl(cocoaWidgetFromHIThemeButtonKind(bdi->kind), &offset); + QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi->kind); + NSButton *bc = (NSButton *)cocoaControl(cw); [bc highlight:pressed]; bc.enabled = bdi->state != kThemeStateUnavailable && bdi->state != kThemeStateUnavailableInactive; bc.allowsMixedState = YES; @@ -2057,9 +2060,7 @@ void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonD QRect rect = opt->rect; if (bdi->kind == kThemePopupButtonMini) rect.adjust(0, 0, -5, 0); - p->translate(offset); - drawNSViewInRect(bc, rect, p); - p->translate(-offset); + drawNSViewInRect(cw, bc, rect, p); return; } else if (usingYosemiteOrLater && editableCombo) { QImage image = activePixmap.toImage(); @@ -3919,15 +3920,14 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter if (hasMenu && yosemiteOrLater && bdi.kind != kThemeBevelButton) { QCocoaWidget w = cocoaWidgetFromHIThemeButtonKind(bdi.kind); + w.first = QCocoaPullDownButton; QPoint offset; - NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(QCocoaWidget(QCocoaPullDownButton, w.second), &offset); + NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(w); [pdb highlight:(bdi.state == kThemeStatePressed)]; pdb.enabled = bdi.state != kThemeStateUnavailable && bdi.state != kThemeStateUnavailableInactive; QRect rect = opt->rect; rect.adjust(0, 0, w.second == QAquaSizeSmall ? -4 : w.second == QAquaSizeMini ? -9 : -6, 0); - p->translate(offset); - d->drawNSViewInRect(pdb, rect, p); - p->translate(-offset); + d->drawNSViewInRect(w, pdb, rect, p); } else if (hasMenu && bdi.state == kThemeStatePressed && QSysInfo::macVersion() > QSysInfo::MV_10_6) d->drawColorlessButton(newRect, &bdi, p, opt); else @@ -5621,12 +5621,13 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex // Yosemite demands its blue progress track when no tickmarks are present if (!(slider->subControls & SC_SliderTickmarks)) { QCocoaWidgetKind sliderKind = slider->orientation == Qt::Horizontal ? QCocoaHorizontalSlider : QCocoaVerticalSlider; - NSSlider *sl = (NSSlider *)d->cocoaControl(QCocoaWidget(sliderKind, QAquaSizeLarge), 0); + QCocoaWidget cw = QCocoaWidget(sliderKind, QAquaSizeLarge); + NSSlider *sl = (NSSlider *)d->cocoaControl(cw); sl.minValue = slider->minimum; sl.maxValue = slider->maximum; sl.intValue = slider->sliderValue; sl.enabled = slider->state & QStyle::State_Enabled; - d->drawNSViewInRect(sl, opt->rect, p, ^(NSRect rect, CGContextRef ctx) { + d->drawNSViewInRect(cw, sl, opt->rect, p, ^(NSRect rect, CGContextRef ctx) { if (slider->upsideDown) { if (isHorizontal) { CGContextTranslateCTM(ctx, rect.size.width, 0); diff --git a/src/widgets/styles/qmacstyle_mac_p_p.h b/src/widgets/styles/qmacstyle_mac_p_p.h index 080f944ef8..8c53dad73e 100644 --- a/src/widgets/styles/qmacstyle_mac_p_p.h +++ b/src/widgets/styles/qmacstyle_mac_p_p.h @@ -204,9 +204,9 @@ public: void setAutoDefaultButton(QObject *button) const; - NSView *cocoaControl(QCocoaWidget widget, QPoint *offset) const; + NSView *cocoaControl(QCocoaWidget widget) const; - void drawNSViewInRect(NSView *view, const QRect &rect, QPainter *p, QCocoaDrawRectBlock drawRectBlock = nil) const; + void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, QCocoaDrawRectBlock drawRectBlock = nil) const; void resolveCurrentNSView(QWindow *window); public: From fc11798e8f5997dd350a9baf39e9a3124b04fdd1 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 17 Oct 2014 14:50:24 +0200 Subject: [PATCH 019/323] QMacStyle: Remove code depending depending on OS X 10.6 and older MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Snow Leopard is unsupported from 5.4.0. Change-Id: I0c49a8353d5dc38169ab9679a986c35ab2df8d2f Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 155 ++++++------------------- src/widgets/styles/qmacstyle_mac_p_p.h | 2 - 2 files changed, 36 insertions(+), 121 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 366de2ff9f..1d4aab7686 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWidgets module of the Qt Toolkit. @@ -296,14 +296,12 @@ void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt, bool isUnified) p->fillRect(rect, QColor(Qt::transparent)); p->restore(); } else if (active) { - int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 16 : 0; - p->fillRect(rect, QColor(151 + d, 151 + d, 151 + d)); + p->fillRect(rect, QColor(167, 167, 167)); } else { - int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 9 : 0; QLinearGradient gradient(rect.topLeft(), rect.bottomLeft()); - gradient.setColorAt(0, QColor(207 + d, 207 + d, 207 + d)); - gradient.setColorAt(0.5, QColor(206 + d, 206 + d, 206 + d)); - gradient.setColorAt(1, QColor(201 + d, 201 + d, 201 + d)); + gradient.setColorAt(0, QColor(216, 216, 216)); + gradient.setColorAt(0.5, QColor(215, 215, 215)); + gradient.setColorAt(1, QColor(210, 210, 210)); p->fillRect(rect, gradient); } @@ -881,13 +879,6 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal; if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr) { int width = 0; - // Snow Leopard and older get a size grip, as well as QMdiSubWindows. - if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_6 -#ifndef QT_NO_MDIAREA - || (widg && widg->parentWidget() && qobject_cast(widg->parentWidget())) -#endif - ) - width = r.size.width; ret = QSize(width, r.size.height); } } @@ -2132,34 +2123,26 @@ QMacStyle::QMacStyle() : QCommonStyle(*new QMacStylePrivate) { Q_D(QMacStyle); -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - d->receiver = [[NotificationReceiver alloc] initWithPrivate:d]; - NotificationReceiver *receiver = static_cast(d->receiver); + d->receiver = [[NotificationReceiver alloc] initWithPrivate:d]; + NotificationReceiver *receiver = static_cast(d->receiver); - [[NSNotificationCenter defaultCenter] addObserver:receiver - selector:@selector(scrollBarStyleDidChange:) - name:NSPreferredScrollerStyleDidChangeNotification - object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:receiver + selector:@selector(scrollBarStyleDidChange:) + name:NSPreferredScrollerStyleDidChangeNotification + object:nil]; - d->nsscroller = [[NSScroller alloc] init]; - } -#endif + d->nsscroller = [[NSScroller alloc] init]; d->indicatorBranchButtonCell = nil; } QMacStyle::~QMacStyle() { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 Q_D(QMacStyle); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - [reinterpret_cast(d->nsscroller) release]; + [reinterpret_cast(d->nsscroller) release]; - NotificationReceiver *receiver = static_cast(d->receiver); - [[NSNotificationCenter defaultCenter] removeObserver:receiver]; - [receiver release]; - } -#endif + NotificationReceiver *receiver = static_cast(d->receiver); + [[NSNotificationCenter defaultCenter] removeObserver:receiver]; + [receiver release]; delete qt_mac_backgroundPattern; qt_mac_backgroundPattern = 0; @@ -2257,7 +2240,7 @@ void QMacStyle::polish(QWidget* w) } if (qobject_cast(w) || qobject_cast(w)) { - w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94); + w->setWindowOpacity(0.985); if (!w->testAttribute(Qt::WA_SetPalette)) { QPixmap px(64, 64); px.fill(Qt::white); @@ -2542,9 +2525,7 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW } break; case PM_ScrollBarExtent: { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 && - [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) { + if ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) { switch (d->aquaSizeConstrain(opt, widget)) { case QAquaSizeUnknown: case QAquaSizeLarge: @@ -2557,7 +2538,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW } break; } -#endif switch (d->aquaSizeConstrain(opt, widget)) { case QAquaSizeUnknown: case QAquaSizeLarge: @@ -2748,13 +2728,8 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW ret = 1; break; case PM_ScrollView_ScrollBarOverlap: -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - ret = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 && - [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) ? + ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay ? pixelMetric(PM_ScrollBarExtent, opt, widget) : 0; -#else - ret = 0; -#endif break; default: ret = QCommonStyle::pixelMetric(metric, opt, widget); @@ -3068,11 +3043,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w if ((qobject_cast(w) && w->parent() && qobject_cast(w->parent()->parent())) || (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))) { - ret = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (ret) - ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay; -#endif + ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay; } break; default: @@ -3779,9 +3750,8 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter alignment |= Qt::TextHideMnemonic; if (down) cr.translate(shiftX, shiftY); - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 - && (tbstyle == Qt::ToolButtonTextOnly - || (tbstyle != Qt::ToolButtonTextOnly && !down))) { + if (tbstyle == Qt::ToolButtonTextOnly + || (tbstyle != Qt::ToolButtonTextOnly && !down)) { QPen pen = p->pen(); QColor light = down ? Qt::black : Qt::white; light.setAlphaF(0.375f); @@ -3796,12 +3766,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } proxy()->drawItemText(p, cr, alignment, pal, tb->state & State_Enabled, tb->text, role); - if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_5 && - (tb->state & State_Sunken)) { - // Draw a "drop shadow" in earlier versions. - proxy()->drawItemText(p, cr.adjusted(0, 1, 0, 1), alignment, - tb->palette, tb->state & State_Enabled, tb->text); - } } } else { QCommonStyle::drawControl(ce, &myTb, p, w); @@ -3928,7 +3892,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QRect rect = opt->rect; rect.adjust(0, 0, w.second == QAquaSizeSmall ? -4 : w.second == QAquaSizeMini ? -9 : -6, 0); d->drawNSViewInRect(w, pdb, rect, p); - } else if (hasMenu && bdi.state == kThemeStatePressed && QSysInfo::macVersion() > QSysInfo::MV_10_6) + } else if (hasMenu && bdi.state == kThemeStatePressed) d->drawColorlessButton(newRect, &bdi, p, opt); else HIThemeDrawButton(&newRect, &bdi, cg, kHIThemeOrientationNormal, 0); @@ -3967,16 +3931,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter if (hasMenu && (!yosemiteOrLater || bdi.kind == kThemeBevelButton)) { int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, w); QRect ir = btn->rect; - int arrowXOffset = 0; - if (QSysInfo::macVersion() > QSysInfo::MV_10_6) - arrowXOffset = bdi.kind == kThemePushButton ? 6 : + int arrowXOffset = bdi.kind == kThemePushButton ? 6 : bdi.kind == kThemePushButtonSmall ? 7 : 8; - int arrowYOffset; - if (QSysInfo::macVersion() > QSysInfo::MV_10_6) - arrowYOffset = bdi.kind == kThemePushButton ? 3 : + int arrowYOffset = bdi.kind == kThemePushButton ? 3 : bdi.kind == kThemePushButtonSmall ? 1 : 2; - else - arrowYOffset = bdi.kind == kThemePushButton ? 4 : 2; if (!w) { // adjustment for Qt Quick Controls arrowYOffset -= ir.top(); @@ -3992,17 +3950,10 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter pdi.version = qt_mac_hitheme_version; pdi.state = tds == kThemeStateInactive ? kThemeStateActive : tds; pdi.orientation = kThemeArrowDown; - if (QSysInfo::macVersion() > QSysInfo::MV_10_6) { - if (bdi.kind == kThemePushButtonMini) - pdi.size = kThemeArrow5pt; - else if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) - pdi.size = kThemeArrow7pt; - } else { - if (arrowRect.size.width < 8.) - pdi.size = kThemeArrow5pt; - else - pdi.size = kThemeArrow9pt; - } + if (bdi.kind == kThemePushButtonMini) + pdi.size = kThemeArrow5pt; + else if (bdi.kind == kThemePushButton || bdi.kind == kThemePushButtonSmall) + pdi.size = kThemeArrow7pt; HIThemeDrawPopupArrow(&arrowRect, &pdi, cg, kHIThemeOrientationNormal); } } @@ -4081,10 +4032,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QRect textRect = itemTextRect( btn.fontMetrics, freeContentRect, Qt::AlignCenter, btn.state & State_Enabled, btn.text); if (hasMenu) { - if (QSysInfo::macVersion() > QSysInfo::MV_10_6) - textRect.moveTo(w ? 15 : 11, textRect.top()); // Supports Qt Quick Controls - else - textRect.adjust(-1, 0, -1, 0); + textRect.moveTo(w ? 15 : 11, textRect.top()); // Supports Qt Quick Controls } // Draw the icon: if (hasIcon) { @@ -4125,7 +4073,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter if (const QStyleOptionComboBox *cb = qstyleoption_cast(opt)) { QStyleOptionComboBox comboCopy = *cb; comboCopy.direction = Qt::LeftToRight; - if ((opt->state & QStyle::State_Small) && QSysInfo::macVersion() > QSysInfo::MV_10_6) + if (opt->state & QStyle::State_Small) comboCopy.rect.translate(0, w ? (QSysInfo::macVersion() > QSysInfo::MV_10_8 ? 0 : -1) : -2); // Supports Qt Quick Controls else if (QSysInfo::macVersion() > QSysInfo::MV_10_8) comboCopy.rect.translate(0, 1); @@ -4264,10 +4212,9 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter ThemeTabDirection ttd = getTabDirection(myTab.shape); bool verticalTabs = ttd == kThemeTabWest || ttd == kThemeTabEast; bool selected = (myTab.state & QStyle::State_Selected); - bool usingLionOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_6; bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9; - if (usingLionOrLater && selected && !myTab.documentMode + if (selected && !myTab.documentMode && (!usingYosemiteOrLater || myTab.state & State_Active)) myTab.palette.setColor(QPalette::WindowText, Qt::white); @@ -4276,7 +4223,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter // outside world, unless they read the source, in which case, it's // their own fault). bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem"); - bool isSelectedAndNeedsShadow = selected && usingLionOrLater && !usingYosemiteOrLater; + bool isSelectedAndNeedsShadow = selected && !usingYosemiteOrLater; if (isSelectedAndNeedsShadow || verticalTabs || nonDefaultFont || !tab->icon.isNull() || !myTab.leftButtonSize.isEmpty() || !myTab.rightButtonSize.isEmpty()) { int heightOffset = 0; @@ -4748,14 +4695,6 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter case CE_ProgressBarGroove: break; case CE_SizeGrip: { - // We do not draw size grips on versions > 10.6 unless it's a QMdiSubWindow - if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_6 -#ifndef QT_NO_MDIAREA - && !(w && w->parentWidget() && qobject_cast(w->parentWidget())) -#endif - ) - break; - if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) { HIThemeGrowBoxDrawInfo gdi; gdi.version = qt_mac_hitheme_version; @@ -5424,7 +5363,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9; const bool isHorizontal = slider->orientation == Qt::Horizontal; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (cc == CC_ScrollBar && proxy()->styleHint(SH_ScrollBar_Transient, opt, widget)) { bool wasActive = false; CGFloat opacity = 0.0; @@ -5587,9 +5525,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex [NSGraphicsContext restoreGraphicsState]; CGContextRestoreGState(cg); - } else -#endif - { + } else { d->stopAnimation(opt->styleObject); if (usingYosemiteOrLater && cc == CC_Slider) { @@ -5861,11 +5797,6 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex uint sc = SC_TitleBarMinButton; ThemeTitleBarWidget tbw = kThemeWidgetCollapseBox; bool active = titlebar->state & State_Active; - if (QSysInfo::macVersion() < QSysInfo::MV_10_6) { - int border = 2; - titleBarRect.origin.x += border; - titleBarRect.origin.y -= border; - } while (sc <= SC_TitleBarCloseButton) { if (sc & titlebar->subControls) { @@ -6004,23 +5935,12 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4); p->setRenderHint(QPainter::Antialiasing); p->fillPath(path, brush); - } else if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) { + } else { static QPixmap pm(QLatin1String(":/qt-project.org/mac/style/images/leopard-unified-toolbar-on.png")); p->save(); p->setRenderHint(QPainter::SmoothPixmapTransform); QStyleHelper::drawBorderPixmap(pm, p, tb->rect, 2, 2, 2, 2); p->restore(); - } else { - QPen oldPen = p->pen(); - p->setPen(QColor(0, 0, 0, 0x3a)); - p->fillRect(tb->rect.adjusted(1, 1, -1, -1), QColor(0, 0, 0, 0x12)); - p->drawLine(tb->rect.left() + 1, tb->rect.top(), - tb->rect.right() - 1, tb->rect.top()); - p->drawLine(tb->rect.left() + 1, tb->rect.bottom(), - tb->rect.right() - 1, tb->rect.bottom()); - p->drawLine(tb->rect.topLeft(), tb->rect.bottomLeft()); - p->drawLine(tb->rect.topRight(), tb->rect.bottomRight()); - p->setPen(oldPen); } } proxy()->drawControl(CE_ToolButtonLabel, opt, p, widget); @@ -6172,10 +6092,7 @@ QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, HIRect macSBRect = qt_hirectForQRect(sb->rect); ControlPartCode part; bool reverseHorizontal = (sb->direction == Qt::RightToLeft - && sb->orientation == Qt::Horizontal - && (!sb->upsideDown || - (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4 - && sb->upsideDown))); + && sb->orientation == Qt::Horizontal); if (HIThemeHitTestScrollBarArrows(&macSBRect, &sbi, sb->orientation == Qt::Horizontal, &pos, 0, &part)) { if (part == kControlUpButtonPart) diff --git a/src/widgets/styles/qmacstyle_mac_p_p.h b/src/widgets/styles/qmacstyle_mac_p_p.h index 8c53dad73e..80b0afe4a4 100644 --- a/src/widgets/styles/qmacstyle_mac_p_p.h +++ b/src/widgets/styles/qmacstyle_mac_p_p.h @@ -222,10 +222,8 @@ public: mutable QPointer focusWidget; CFAbsoluteTime defaultButtonStart; bool mouseDown; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 void* receiver; void *nsscroller; -#endif void *indicatorBranchButtonCell; NSView *backingStoreNSView; QHash cocoaControls; From a198ce8d8fe9b418d631d033d481ec38f0373fa4 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 17 Oct 2014 15:16:12 +0200 Subject: [PATCH 020/323] Cocoa QPA Plugin: Remove code depending depending on OS X 10.6 and older Snow Leopard is unsupported from 5.4.0. Change-Id: I5c269cbdc93000a4657b63559cc3c526e298e3db Reviewed-by: Gabriel de Dietrich --- .../cocoa/qcocoacolordialoghelper.mm | 7 +- .../platforms/cocoa/qcocoafontdialoghelper.mm | 6 +- .../platforms/cocoa/qcocoaintegration.mm | 13 +- .../platforms/cocoa/qcocoaintrospection.mm | 52 ++-- .../platforms/cocoa/qcocoaprintdevice.mm | 4 - src/plugins/platforms/cocoa/qcocoawindow.mm | 126 +++----- src/plugins/platforms/cocoa/qnsview.mm | 122 +++----- .../platforms/cocoa/qpaintengine_mac.mm | 280 ++++++------------ 8 files changed, 187 insertions(+), 423 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 8158c244ab..7d99f566bf 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -106,10 +106,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mResultSet = false; mClosingDueToKnownButton = false; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) - [mColorPanel setRestorable:NO]; -#endif + [mColorPanel setRestorable:NO]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(colorChanged:) diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index c37bb63916..f5e22d1125 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -149,11 +149,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); mDialogIsExecuting = false; mResultSet = false; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) - [mFontPanel setRestorable:NO]; -#endif - + [mFontPanel setRestorable:NO]; [mFontPanel setDelegate:self]; [[NSFontManager sharedFontManager] setDelegate:self]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index e0838cb342..72bd09625a 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -144,15 +144,8 @@ void QCocoaScreen::updateGeometry() qreal QCocoaScreen::devicePixelRatio() const { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - NSScreen * screen = osScreen(); - return qreal(screen ? [screen backingScaleFactor] : 1.0); - } else -#endif - { - return 1.0; - } + NSScreen * screen = osScreen(); + return qreal(screen ? [screen backingScaleFactor] : 1.0); } QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm index 806effc929..84b16813dc 100644 --- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm +++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -79,43 +79,33 @@ QT_BEGIN_NAMESPACE void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class proxyClass, SEL replacementSel, SEL backupSel) { -#ifndef QT_MAC_USE_COCOA - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) -#endif - { - // The following code replaces the _implementation_ for the selector we want to hack - // (originalSel) with the implementation found in proxyClass. Then it creates - // a new 'backup' method inside baseClass containing the old, original, - // implementation (fakeSel). You can let the proxy implementation of originalSel - // call fakeSel if needed (similar approach to calling a super class implementation). - // fakeSel must also be implemented in proxyClass, as the signature is used - // as template for the method one we add into baseClass. - // NB: You will typically never create any instances of proxyClass; we use it - // only for stealing its contents and put it into baseClass. - if (!replacementSel) - replacementSel = originalSel; + // The following code replaces the _implementation_ for the selector we want to hack + // (originalSel) with the implementation found in proxyClass. Then it creates + // a new 'backup' method inside baseClass containing the old, original, + // implementation (fakeSel). You can let the proxy implementation of originalSel + // call fakeSel if needed (similar approach to calling a super class implementation). + // fakeSel must also be implemented in proxyClass, as the signature is used + // as template for the method one we add into baseClass. + // NB: You will typically never create any instances of proxyClass; we use it + // only for stealing its contents and put it into baseClass. + if (!replacementSel) + replacementSel = originalSel; - Method originalMethod = class_getInstanceMethod(baseClass, originalSel); - Method replacementMethod = class_getInstanceMethod(proxyClass, replacementSel); - IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(replacementMethod)); + Method originalMethod = class_getInstanceMethod(baseClass, originalSel); + Method replacementMethod = class_getInstanceMethod(proxyClass, replacementSel); + IMP originalImp = method_setImplementation(originalMethod, method_getImplementation(replacementMethod)); - if (backupSel) { - Method backupMethod = class_getInstanceMethod(proxyClass, backupSel); - class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod)); - } + if (backupSel) { + Method backupMethod = class_getInstanceMethod(proxyClass, backupSel); + class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod)); } } void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL backupSel) { -#ifndef QT_MAC_USE_COCOA - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) -#endif - { - Method originalMethod = class_getInstanceMethod(baseClass, originalSel); - Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel); - method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass)); - } + Method originalMethod = class_getInstanceMethod(baseClass, originalSel); + Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel); + method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass)); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index 2101b68769..b3551e2c29 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -466,11 +466,7 @@ bool QCocoaPrintDevice::openPpdFile() ppdClose(m_ppd); m_ppd = 0; CFURLRef ppdURL = NULL; -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 - char ppdPath[PATH_MAX]; -#else char ppdPath[MAXPATHLEN]; -#endif if (PMPrinterCopyDescriptionURL(m_printer, kPMPPDDescriptionType, &ppdURL) == noErr && ppdURL != NULL && CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath))) { diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 60c772702c..ad6390788a 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -107,26 +107,6 @@ static void selectNextKeyWindow(NSWindow *currentKeyWindow) } } - -@interface NSWindow (CocoaWindowCategory) -- (NSRect) legacyConvertRectFromScreen:(NSRect) rect; -@end - -@implementation NSWindow (CocoaWindowCategory) -- (NSRect) legacyConvertRectFromScreen:(NSRect) rect -{ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - return [self convertRectFromScreen: rect]; - } -#endif - NSRect r = rect; - r.origin = [self convertScreenToBase:rect.origin]; - return r; -} -@end - - @implementation QNSWindowHelper @synthesize window = _window; @@ -197,7 +177,7 @@ static void selectNextKeyWindow(NSWindow *currentKeyWindow) if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { NSPoint loc = [theEvent locationInWindow]; - NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]]; + NSRect windowFrame = [self.window convertRectFromScreen:[self.window frame]]; NSRect contentFrame = [[self.window contentView] frame]; if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO)) @@ -432,19 +412,16 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) } else { m_qtView = [[QNSView alloc] initWithQWindow:tlw platformWindow:this]; m_contentView = m_qtView; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 // Enable high-dpi OpenGL for retina displays. Enabling has the side // effect that Cocoa will start calling glViewport(0, 0, width, height), // overriding any glViewport calls in application code. This is usually not a // problem, except if the appilcation wants to have a "custom" viewport. // (like the hellogl example) - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 - && tlw->supportsOpenGL()) { + if (tlw->supportsOpenGL()) { BOOL enable = qt_mac_resolveOption(YES, tlw, "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); [m_contentView setWantsBestResolutionOpenGLSurface:enable]; } -#endif BOOL enable = qt_mac_resolveOption(NO, tlw, "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); [m_contentView setWantsLayer:enable]; @@ -516,7 +493,8 @@ QRect QCocoaWindow::geometry() const // of view. Embedded QWindows get global (screen) geometry. if (m_contentViewIsEmbedded) { NSPoint windowPoint = [m_contentView convertPoint:NSMakePoint(0, 0) toView:nil]; - NSPoint screenPoint = [[m_contentView window] convertBaseToScreen:windowPoint]; // ### use convertRectToScreen after 10.6 removal + NSRect screenRect = [[m_contentView window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)]; + NSPoint screenPoint = screenRect.origin; QPoint position = qt_mac_flipPoint(screenPoint).toPoint(); QSize size = qt_mac_toQRect([m_contentView bounds]).size(); return QRect(position, size); @@ -681,11 +659,7 @@ void QCocoaWindow::setVisible(bool visible) // Since this isn't a native popup, the window manager doesn't close the popup when you click outside NSUInteger parentStyleMask = [parentCocoaWindow->m_nsWindow styleMask]; if ((m_resizableTransientParent = (parentStyleMask & NSResizableWindowMask)) -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - && QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 - && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask) -#endif - ) + && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask)) [parentCocoaWindow->m_nsWindow setStyleMask:parentStyleMask & ~NSResizableWindowMask]; } @@ -784,11 +758,7 @@ void QCocoaWindow::setVisible(bool visible) if (parentCocoaWindow && window()->type() == Qt::Popup) { parentCocoaWindow->m_activePopupWindow = 0; if (m_resizableTransientParent -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - && QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 - && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask) -#endif - ) + && !([parentCocoaWindow->m_nsWindow styleMask] & NSFullScreenWindowMask)) // QTBUG-30266: a window should not be resizable while a transient popup is open [parentCocoaWindow->m_nsWindow setStyleMask:[parentCocoaWindow->m_nsWindow styleMask] | NSResizableWindowMask]; } @@ -903,19 +873,15 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) setWindowTitle(window()->title()); } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - Qt::WindowType type = window()->type(); - if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) { - NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior]; - if (flags & Qt::WindowFullscreenButtonHint) - behavior |= NSWindowCollectionBehaviorFullScreenPrimary; - else - behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; - [m_nsWindow setCollectionBehavior:behavior]; - } + Qt::WindowType type = window()->type(); + if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) { + NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior]; + if (flags & Qt::WindowFullscreenButtonHint) + behavior |= NSWindowCollectionBehaviorFullScreenPrimary; + else + behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary; + [m_nsWindow setCollectionBehavior:behavior]; } -#endif setWindowZoomButton(flags); } @@ -1340,13 +1306,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindow.hasShadow = NO; m_nsWindow.level = NSNormalWindowLevel; NSWindowCollectionBehavior collectionBehavior = - NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary; - m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; - } -#endif + NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle + | NSWindowCollectionBehaviorFullScreenAuxiliary; + m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; m_nsWindow.collectionBehavior = collectionBehavior; setCocoaGeometry(window()->geometry()); @@ -1440,15 +1402,11 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - // Make popup winows show on the same desktop as the parent full-screen window. - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + // Make popup windows show on the same desktop as the parent full-screen window. + [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + if ((type & Qt::Popup) == Qt::Popup) + [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow]; - if ((type & Qt::Popup) == Qt::Popup) - [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow]; - } -#endif createdWindow = window; } else { QNSWindow *window; @@ -1458,10 +1416,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() createdWindow = window; } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([createdWindow respondsToSelector:@selector(setRestorable:)]) [createdWindow setRestorable: NO]; -#endif NSInteger level = windowLevel(flags); [createdWindow setLevel:level]; @@ -1562,18 +1518,11 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { - bool fakeFullScreen = true; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - if (window()->flags() & Qt::WindowFullscreenButtonHint) { - fakeFullScreen = false; - if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen) - predictedState = Qt::WindowMaximized; - [m_nsWindow toggleFullScreen : m_nsWindow]; - } - } -#endif - if (fakeFullScreen) { + if (window()->flags() & Qt::WindowFullscreenButtonHint) { + if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen) + predictedState = Qt::WindowMaximized; + [m_nsWindow toggleFullScreen : m_nsWindow]; + } else { if (newState & Qt::WindowFullScreen) { QScreen *screen = window()->screen(); if (screen) { @@ -1747,20 +1696,13 @@ bool QCocoaWindow::testContentBorderAreaPosition(int position) const qreal QCocoaWindow::devicePixelRatio() const { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - // The documented way to observe the relationship between device-independent - // and device pixels is to use one for the convertToBacking functions. Other - // methods such as [NSWindow backingScaleFacor] might not give the correct - // result, for example if setWantsBestResolutionOpenGLSurface is not set or - // or ignored by the OpenGL driver. - NSSize backingSize = [m_contentView convertSizeToBacking:NSMakeSize(1.0, 1.0)]; - return backingSize.height; - } else -#endif - { - return 1.0; - } + // The documented way to observe the relationship between device-independent + // and device pixels is to use one for the convertToBacking functions. Other + // methods such as [NSWindow backingScaleFacor] might not give the correct + // result, for example if setWantsBestResolutionOpenGLSurface is not set or + // or ignored by the OpenGL driver. + NSSize backingSize = [m_contentView convertSizeToBacking:NSMakeSize(1.0, 1.0)]; + return backingSize.height; } // Returns whether the window can be expose, which it can diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index b33f71fd46..458e0ff924 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -408,10 +408,6 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; Qt::WindowState newState = notificationName == NSWindowDidMiniaturizeNotification ? Qt::WindowMinimized : Qt::WindowNoState; [self notifyWindowStateChanged:newState]; - // NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not - // emitted in 10.6, so we bring back the old behavior for that case alone. - if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6) - m_platformWindow->exposeWindow(); } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { m_platformWindow->obscureWindow(); } else if ([notificationName isEqualToString: @"NSWindowDidOrderOnScreenAndFinishAnimatingNotification"]) { @@ -442,19 +438,11 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->updateExposedGeometry(); } } - } else { - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - if (notificationName == NSWindowDidEnterFullScreenNotification - || notificationName == NSWindowDidExitFullScreenNotification) { - Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ? - Qt::WindowFullScreen : Qt::WindowNoState; - [self notifyWindowStateChanged:newState]; - } - } -#endif - + } else if (notificationName == NSWindowDidEnterFullScreenNotification + || notificationName == NSWindowDidExitFullScreenNotification) { + Qt::WindowState newState = notificationName == NSWindowDidEnterFullScreenNotification ? + Qt::WindowFullScreen : Qt::WindowNoState; + [self notifyWindowStateChanged:newState]; } } @@ -656,16 +644,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; NSWindow *window = [self window]; NSPoint nsWindowPoint; - // Use convertRectToScreen if available (added in 10.7). -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if ([window respondsToSelector:@selector(convertRectFromScreen:)]) { - NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)]; - nsWindowPoint = windowRect.origin; // NSWindow coordinates - } else -#endif - { - nsWindowPoint = [window convertScreenToBase:mouseLocation]; // NSWindow coordinates - } + NSRect windowRect = [window convertRectFromScreen:NSMakeRect(mouseLocation.x, mouseLocation.y, 1, 1)]; + nsWindowPoint = windowRect.origin; // NSWindow coordinates NSPoint nsViewPoint = [self convertPoint: nsWindowPoint fromView: nil]; // NSView/QWindow coordinates *qtWindowPoint = QPointF(nsViewPoint.x, nsViewPoint.y); // NSView/QWindow coordinates @@ -1296,18 +1276,8 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) // It looks like 1/4 degrees per pixel behaves most native. // (NB: Qt expects the unit for delta to be 8 per degree): const int pixelsToDegrees = 2; // 8 * 1/4 - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { - angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees); - angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees); - } else -#endif - { - angleDelta.setX([theEvent deviceDeltaX] * pixelsToDegrees); - angleDelta.setY([theEvent deviceDeltaY] * pixelsToDegrees); - } - + angleDelta.setX([theEvent scrollingDeltaX] * pixelsToDegrees); + angleDelta.setY([theEvent scrollingDeltaY] * pixelsToDegrees); } else { // carbonEventKind == kEventMouseWheelMoved // Remove acceleration, and use either -120 or 120 as delta: @@ -1316,20 +1286,16 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) } QPoint pixelDelta; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { - if ([theEvent hasPreciseScrollingDeltas]) { - pixelDelta.setX([theEvent scrollingDeltaX]); - pixelDelta.setY([theEvent scrollingDeltaY]); - } else { - // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width." - // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels. - const CGFloat lineWithEstimate = 20.0; - pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate); - pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate); - } + if ([theEvent hasPreciseScrollingDeltas]) { + pixelDelta.setX([theEvent scrollingDeltaX]); + pixelDelta.setY([theEvent scrollingDeltaY]); + } else { + // docs: "In the case of !hasPreciseScrollingDeltas, multiply the delta with the line width." + // scrollingDeltaX seems to return a minimum value of 0.1 in this case, map that to two pixels. + const CGFloat lineWithEstimate = 20.0; + pixelDelta.setX([theEvent scrollingDeltaX] * lineWithEstimate); + pixelDelta.setY([theEvent scrollingDeltaY] * lineWithEstimate); } -#endif QPointF qt_windowPoint; QPointF qt_screenPoint; @@ -1337,44 +1303,36 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { - // Prevent keyboard modifier state from changing during scroll event streams. - // A two-finger trackpad flick generates a stream of scroll events. We want - // the keyboard modifier state to be the state at the beginning of the - // flick in order to avoid changing the interpretation of the events - // mid-stream. One example of this happening would be when pressing cmd - // after scrolling in Qt Creator: not taking the phase into account causes - // the end of the event stream to be interpreted as font size changes. - NSEventPhase momentumPhase = [theEvent momentumPhase]; - if (momentumPhase == NSEventPhaseNone) { - currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; - } + // Prevent keyboard modifier state from changing during scroll event streams. + // A two-finger trackpad flick generates a stream of scroll events. We want + // the keyboard modifier state to be the state at the beginning of the + // flick in order to avoid changing the interpretation of the events + // mid-stream. One example of this happening would be when pressing cmd + // after scrolling in Qt Creator: not taking the phase into account causes + // the end of the event stream to be interpreted as font size changes. + NSEventPhase momentumPhase = [theEvent momentumPhase]; + if (momentumPhase == NSEventPhaseNone) { + currentWheelModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; + } - NSEventPhase phase = [theEvent phase]; - Qt::ScrollPhase ph = Qt::ScrollUpdate; + NSEventPhase phase = [theEvent phase]; + Qt::ScrollPhase ph = Qt::ScrollUpdate; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { - // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. - if (phase == NSEventPhaseMayBegin) - ph = Qt::ScrollBegin; - } else + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { + // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. + if (phase == NSEventPhaseMayBegin) + ph = Qt::ScrollBegin; + } else #endif if (phase == NSEventPhaseBegan) { // On 10.7, MayBegin will not happen, so Began is the actual beginning. ph = Qt::ScrollBegin; } - if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { - ph = Qt::ScrollEnd; - } - - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); - } else -#endif - { - QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, - [QNSView convertKeyModifiers:[theEvent modifierFlags]]); + if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled) { + ph = Qt::ScrollEnd; } + + QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); } #endif //QT_NO_WHEELEVENT diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index d48cbdfac8..7b77c9f1a8 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -90,20 +90,13 @@ static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransfor if (rgn.isEmpty()) { CGContextAddRect(hd, CGRectMake(0, 0, 0, 0)); } else { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) { - QCFType shape = qt_mac_QRegionToHIMutableShape(rgn); - Q_ASSERT(!HIShapeIsEmpty(shape)); - HIShapeReplacePathInCGContext(shape, hd); - } else { - QVector rects = rgn.rects(); - const int count = rects.size(); - for (int i = 0; i < count; i++) { - const QRect &r = rects[i]; - CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height()); - CGContextAddRect(hd, mac_r); - } + QVector rects = rgn.rects(); + const int count = rects.size(); + for (int i = 0; i < count; i++) { + const QRect &r = rects[i]; + CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height()); + CGContextAddRect(hd, mac_r); } - } CGContextClip(hd); @@ -1137,184 +1130,85 @@ extern "C" { void QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) { - int cg_mode = kCGBlendModeNormal; - switch (mode) { - case QPainter::CompositionMode_Multiply: - cg_mode = kCGBlendModeMultiply; - break; - case QPainter::CompositionMode_Screen: - cg_mode = kCGBlendModeScreen; - break; - case QPainter::CompositionMode_Overlay: - cg_mode = kCGBlendModeOverlay; - break; - case QPainter::CompositionMode_Darken: - cg_mode = kCGBlendModeDarken; - break; - case QPainter::CompositionMode_Lighten: - cg_mode = kCGBlendModeLighten; - break; - case QPainter::CompositionMode_ColorDodge: - cg_mode = kCGBlendModeColorDodge; - break; - case QPainter::CompositionMode_ColorBurn: - cg_mode = kCGBlendModeColorBurn; - break; - case QPainter::CompositionMode_HardLight: - cg_mode = kCGBlendModeHardLight; - break; - case QPainter::CompositionMode_SoftLight: - cg_mode = kCGBlendModeSoftLight; - break; - case QPainter::CompositionMode_Difference: - cg_mode = kCGBlendModeDifference; - break; - case QPainter::CompositionMode_Exclusion: - cg_mode = kCGBlendModeExclusion; - break; - case QPainter::CompositionMode_Plus: - cg_mode = kCGBlendModePlusLighter; - break; - case QPainter::CompositionMode_SourceOver: - cg_mode = kCGBlendModeNormal; - break; - case QPainter::CompositionMode_DestinationOver: - cg_mode = kCGBlendModeDestinationOver; - break; - case QPainter::CompositionMode_Clear: - cg_mode = kCGBlendModeClear; - break; - case QPainter::CompositionMode_Source: - cg_mode = kCGBlendModeCopy; - break; - case QPainter::CompositionMode_Destination: - cg_mode = -1; - break; - case QPainter::CompositionMode_SourceIn: - cg_mode = kCGBlendModeSourceIn; - break; - case QPainter::CompositionMode_DestinationIn: - cg_mode = kCGCompositeModeDestinationIn; - break; - case QPainter::CompositionMode_SourceOut: - cg_mode = kCGBlendModeSourceOut; - break; - case QPainter::CompositionMode_DestinationOut: - cg_mode = kCGBlendModeDestinationOver; - break; - case QPainter::CompositionMode_SourceAtop: - cg_mode = kCGBlendModeSourceAtop; - break; - case QPainter::CompositionMode_DestinationAtop: - cg_mode = kCGBlendModeDestinationAtop; - break; - case QPainter::CompositionMode_Xor: - cg_mode = kCGBlendModeXOR; - break; - default: - break; - } - if (cg_mode > -1) { - CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode)); - } - } else if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3 - && mode <= QPainter::CompositionMode_Xor) { - // The standard porter duff ops. - int cg_mode = kCGCompositeModeCopy; - switch (mode) { - case QPainter::CompositionMode_SourceOver: - cg_mode = kCGCompositeModeSourceOver; - break; - case QPainter::CompositionMode_DestinationOver: - cg_mode = kCGCompositeModeDestinationOver; - break; - case QPainter::CompositionMode_Clear: - cg_mode = kCGCompositeModeClear; - break; - default: - qWarning("QCoreGraphicsPaintEngine: Unhandled composition mode %d", (int)mode); - break; - case QPainter::CompositionMode_Source: - cg_mode = kCGCompositeModeCopy; - break; - case QPainter::CompositionMode_Destination: - cg_mode = CGCompositeMode(-1); - break; - case QPainter::CompositionMode_SourceIn: - cg_mode = kCGCompositeModeSourceIn; - break; - case QPainter::CompositionMode_DestinationIn: - cg_mode = kCGCompositeModeDestinationIn; - break; - case QPainter::CompositionMode_SourceOut: - cg_mode = kCGCompositeModeSourceOut; - break; - case QPainter::CompositionMode_DestinationOut: - cg_mode = kCGCompositeModeDestinationOut; - break; - case QPainter::CompositionMode_SourceAtop: - cg_mode = kCGCompositeModeSourceAtop; - break; - case QPainter::CompositionMode_DestinationAtop: - cg_mode = kCGCompositeModeDestinationAtop; - break; - case QPainter::CompositionMode_Xor: - cg_mode = kCGCompositeModeXOR; - break; - } - if (cg_mode > -1) - CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode)); - } else { - bool needPrivateAPI = false; - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - int cg_mode = kCGBlendModeNormal; - switch (mode) { - case QPainter::CompositionMode_Multiply: - cg_mode = kCGBlendModeMultiply; - break; - case QPainter::CompositionMode_Screen: - cg_mode = kCGBlendModeScreen; - break; - case QPainter::CompositionMode_Overlay: - cg_mode = kCGBlendModeOverlay; - break; - case QPainter::CompositionMode_Darken: - cg_mode = kCGBlendModeDarken; - break; - case QPainter::CompositionMode_Lighten: - cg_mode = kCGBlendModeLighten; - break; - case QPainter::CompositionMode_ColorDodge: - cg_mode = kCGBlendModeColorDodge; - break; - case QPainter::CompositionMode_ColorBurn: - cg_mode = kCGBlendModeColorBurn; - break; - case QPainter::CompositionMode_HardLight: - cg_mode = kCGBlendModeHardLight; - break; - case QPainter::CompositionMode_SoftLight: - cg_mode = kCGBlendModeSoftLight; - break; - case QPainter::CompositionMode_Difference: - cg_mode = kCGBlendModeDifference; - break; - case QPainter::CompositionMode_Exclusion: - cg_mode = kCGBlendModeExclusion; - break; - case QPainter::CompositionMode_Plus: - needPrivateAPI = true; - cg_mode = kCGCompositeModePlusLighter; - break; - default: - break; - } - if (!needPrivateAPI) - CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode)); - else - CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode)); - } + int cg_mode = kCGBlendModeNormal; + switch (mode) { + case QPainter::CompositionMode_Multiply: + cg_mode = kCGBlendModeMultiply; + break; + case QPainter::CompositionMode_Screen: + cg_mode = kCGBlendModeScreen; + break; + case QPainter::CompositionMode_Overlay: + cg_mode = kCGBlendModeOverlay; + break; + case QPainter::CompositionMode_Darken: + cg_mode = kCGBlendModeDarken; + break; + case QPainter::CompositionMode_Lighten: + cg_mode = kCGBlendModeLighten; + break; + case QPainter::CompositionMode_ColorDodge: + cg_mode = kCGBlendModeColorDodge; + break; + case QPainter::CompositionMode_ColorBurn: + cg_mode = kCGBlendModeColorBurn; + break; + case QPainter::CompositionMode_HardLight: + cg_mode = kCGBlendModeHardLight; + break; + case QPainter::CompositionMode_SoftLight: + cg_mode = kCGBlendModeSoftLight; + break; + case QPainter::CompositionMode_Difference: + cg_mode = kCGBlendModeDifference; + break; + case QPainter::CompositionMode_Exclusion: + cg_mode = kCGBlendModeExclusion; + break; + case QPainter::CompositionMode_Plus: + cg_mode = kCGBlendModePlusLighter; + break; + case QPainter::CompositionMode_SourceOver: + cg_mode = kCGBlendModeNormal; + break; + case QPainter::CompositionMode_DestinationOver: + cg_mode = kCGBlendModeDestinationOver; + break; + case QPainter::CompositionMode_Clear: + cg_mode = kCGBlendModeClear; + break; + case QPainter::CompositionMode_Source: + cg_mode = kCGBlendModeCopy; + break; + case QPainter::CompositionMode_Destination: + cg_mode = -1; + break; + case QPainter::CompositionMode_SourceIn: + cg_mode = kCGBlendModeSourceIn; + break; + case QPainter::CompositionMode_DestinationIn: + cg_mode = kCGCompositeModeDestinationIn; + break; + case QPainter::CompositionMode_SourceOut: + cg_mode = kCGBlendModeSourceOut; + break; + case QPainter::CompositionMode_DestinationOut: + cg_mode = kCGBlendModeDestinationOver; + break; + case QPainter::CompositionMode_SourceAtop: + cg_mode = kCGBlendModeSourceAtop; + break; + case QPainter::CompositionMode_DestinationAtop: + cg_mode = kCGBlendModeDestinationAtop; + break; + case QPainter::CompositionMode_Xor: + cg_mode = kCGBlendModeXOR; + break; + default: + break; + } + if (cg_mode > -1) { + CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode)); } } @@ -1645,8 +1539,6 @@ void QCoreGraphicsPaintEnginePrivate::drawPath(uchar ops, CGMutablePathRef path) if (!(q->state->renderHints() & QPainter::Antialiasing)) { if (current.pen.style() == Qt::SolidLine || current.pen.width() >= 3) CGContextTranslateCTM(hd, double(pixelSize.x()) * 0.25, double(pixelSize.y()) * 0.25); - else if (current.pen.style() == Qt::DotLine && QSysInfo::MacintoshVersion == QSysInfo::MV_10_3) - ; // Do nothing. else CGContextTranslateCTM(hd, 0, double(pixelSize.y()) * 0.1); } From 41ece1cbc120db5c7f51f08629845d5dfa2f34b8 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Fri, 24 Oct 2014 14:45:03 +0400 Subject: [PATCH 021/323] Fix includes in mousebuttons example Remove QtWidgets from buttontester.h and QtGui from main.cpp. Change-Id: Ie5925a33c58c1abd9747ab0ab7040e7d1b0769a9 Reviewed-by: Friedemann Kleint --- examples/widgets/widgets/mousebuttons/buttontester.cpp | 2 ++ examples/widgets/widgets/mousebuttons/buttontester.h | 2 -- examples/widgets/widgets/mousebuttons/main.cpp | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/widgets/widgets/mousebuttons/buttontester.cpp b/examples/widgets/widgets/mousebuttons/buttontester.cpp index 41c6c95adf..51287f541b 100644 --- a/examples/widgets/widgets/mousebuttons/buttontester.cpp +++ b/examples/widgets/widgets/mousebuttons/buttontester.cpp @@ -41,6 +41,8 @@ #include "buttontester.h" +#include + void ButtonTester::mousePressEvent(QMouseEvent *e) { int j = ButtonTester::buttonByNumber (e->button()); diff --git a/examples/widgets/widgets/mousebuttons/buttontester.h b/examples/widgets/widgets/mousebuttons/buttontester.h index 9e7011ac9a..41ae8d0582 100644 --- a/examples/widgets/widgets/mousebuttons/buttontester.h +++ b/examples/widgets/widgets/mousebuttons/buttontester.h @@ -41,10 +41,8 @@ #ifndef BUTTONTESTER_H #define BUTTONTESTER_H -#include #include #include -#include #include #include diff --git a/examples/widgets/widgets/mousebuttons/main.cpp b/examples/widgets/widgets/mousebuttons/main.cpp index 184547113e..b5446df9e9 100644 --- a/examples/widgets/widgets/mousebuttons/main.cpp +++ b/examples/widgets/widgets/mousebuttons/main.cpp @@ -40,7 +40,10 @@ ****************************************************************************/ #include "buttontester.h" -#include + +#include +#include +#include int main(int argv, char **args) { From 7bda05eb380287836884643eecae8632da04781c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 27 Oct 2014 09:42:08 +0100 Subject: [PATCH 022/323] iOS: update qtmn doc to use the actual function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I62b656a317298ec40117017d74fca1be262a66b7 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qioseventdispatcher.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index ce7dfe2606..66fd9cd1e5 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -241,11 +241,11 @@ enum SetJumpResult kJumpedFromUserMainTrampoline, }; -// We define qt_main so that user_main_trampoline() will not cause +// We define qtmn so that user_main_trampoline() will not cause // missing symbols in the case of hybrid applications that don't -// user our main wrapper. Since the symbol is weak, it will not +// use our main wrapper. Since the symbol is weak, it will not // get used or cause a clash in the normal Qt application usecase, -// where we rename main to qt_main. +// where we rename main to qtmn before linking. extern "C" int __attribute__((weak)) qtmn(int argc, char *argv[]) { Q_UNUSED(argc); From 44654675ed9e284c090029611822f6e93828440a Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Sun, 26 Oct 2014 10:08:38 +1000 Subject: [PATCH 023/323] Do not add invalid configurations to bearermonitor If the list of configurations takes time in the backend, the defaultConfiguration will be invalid at this time, but will be updated by the backend. Change-Id: I2886a8f6c569c993814172ccaa46e4bb5ba5e0d6 Reviewed-by: Alex Blasche --- examples/network/bearermonitor/bearermonitor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/network/bearermonitor/bearermonitor.cpp b/examples/network/bearermonitor/bearermonitor.cpp index 4590a91f4f..2f5d6cda1c 100644 --- a/examples/network/bearermonitor/bearermonitor.cpp +++ b/examples/network/bearermonitor/bearermonitor.cpp @@ -127,6 +127,9 @@ static void updateItem(QTreeWidgetItem *item, const QNetworkConfiguration &confi void BearerMonitor::configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent) { + if (!config.isValid()) + return; + QTreeWidgetItem *item = new QTreeWidgetItem; updateItem(item, config); From 6080db8c6d345cf4ad573215828246e86f9dc41b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 14 Oct 2014 16:58:01 +0200 Subject: [PATCH 024/323] Check geometry correctly when replaying popup mouse events. Task-number: QTBUG-41869 Task-number: QTBUG-39313 Change-Id: I2b59f5db6f0ae4007b1a3b58a79eed958e662272 Reviewed-by: Laszlo Agocs --- src/widgets/kernel/qwidgetwindow.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index d40fc84d77..1cd042f99d 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -433,14 +433,19 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event) QWindow *win = w->windowHandle(); if (!win) win = w->nativeParentWidget()->windowHandle(); - if (win && win->geometry().contains(event->globalPos())) { - // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec() - const QPoint localPos = win->mapFromGlobal(event->globalPos()); - QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPos(), event->button(), event->buttons(), event->modifiers()); - QCoreApplicationPrivate::setEventSpontaneous(e, true); - QGuiApplicationPrivate::setMouseEventSource(e, QGuiApplicationPrivate::mouseEventSource(event)); - e->setTimestamp(event->timestamp()); - QCoreApplication::postEvent(win, e); + if (win) { + const QRect globalGeometry = win->isTopLevel() + ? win->geometry() + : QRect(win->mapToGlobal(QPoint(0, 0)), win->size()); + if (globalGeometry.contains(event->globalPos())) { + // Use postEvent() to ensure the local QEventLoop terminates when called from QMenu::exec() + const QPoint localPos = win->mapFromGlobal(event->globalPos()); + QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress, localPos, localPos, event->globalPos(), event->button(), event->buttons(), event->modifiers()); + QCoreApplicationPrivate::setEventSpontaneous(e, true); + QGuiApplicationPrivate::setMouseEventSource(e, QGuiApplicationPrivate::mouseEventSource(event)); + e->setTimestamp(event->timestamp()); + QCoreApplication::postEvent(win, e); + } } } } From 1abcc1cd3d1a8d04ccfd711c3293d0c671af3c78 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 27 Oct 2014 10:45:47 +0100 Subject: [PATCH 025/323] Hardcode UTF-8 for "unicode" in QTextCodec::codecForHtml(). ICU would return a utf-16 (endian dependent) codec for unicode which is very rarely what people want. In most cases, unicode is encoded in utf8 these days, so return a utf8 codec for it. Task-number: QTBUG-41998 Change-Id: I51ee758d520702b263a8b2011787eb1f3455ed96 Reviewed-by: Lars Knoll --- src/corelib/codecs/qtextcodec.cpp | 5 ++++- tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 24cb4e7038..9af307ca17 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -1049,7 +1049,10 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo while (++pos2 < header.size()) { char ch = header.at(pos2); if (ch == '\"' || ch == '\'' || ch == '>') { - c = QTextCodec::codecForName(header.mid(pos, pos2 - pos)); + QByteArray name = header.mid(pos, pos2 - pos); + if (name == "unicode") // QTBUG-41998, ICU will return UTF-16. + name = QByteArrayLiteral("UTF-8"); + c = QTextCodec::codecForName(name); return c ? c : defaultCodec; } } diff --git a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp index 4e3d5c64bc..df2f97ce0e 100644 --- a/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp +++ b/tests/auto/corelib/codecs/qtextcodec/tst_qtextcodec.cpp @@ -1996,6 +1996,10 @@ void tst_QTextCodec::codecForHtml_data() "auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; display: inline !important; float: " "none;\">ͻ\000"; QTest::newRow("greek text UTF-8") << html << 106 << 106; + + html = "" + "

bla

"; // QTBUG-41998, ICU will return UTF-16. + QTest::newRow("legacy unicode UTF-8") << html << 106 << 106; } void tst_QTextCodec::codecForHtml() From 50bba2fbfb7e80d9aa8d6da2575e8617e9b7471c Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 23 Oct 2014 17:44:57 +0200 Subject: [PATCH 026/323] Fix tst_QAccessibility::abstractScrollAreaTest for OS X 10.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OS X now has a setting (General->Show scroll bars) to use only transient scroll bars. Task-number: QTBUG-41340 Change-Id: Iffe30e9d601c169d955a380002743bab518f41ea Reviewed-by: Jan Arve Sæther --- tests/auto/other/qaccessibility/BLACKLIST | 2 - .../qaccessibility/tst_qaccessibility.cpp | 38 ++++++++++++------- 2 files changed, 24 insertions(+), 16 deletions(-) delete mode 100644 tests/auto/other/qaccessibility/BLACKLIST diff --git a/tests/auto/other/qaccessibility/BLACKLIST b/tests/auto/other/qaccessibility/BLACKLIST deleted file mode 100644 index 11598aece6..0000000000 --- a/tests/auto/other/qaccessibility/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[abstractScrollAreaTest] -osx diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index e6bcc33771..ef70509541 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -2654,57 +2654,67 @@ void tst_QAccessibility::abstractScrollAreaTest() // Horizontal scrollBar. abstractScrollArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - QCOMPARE(interface->childCount(), 2); QWidget *horizontalScrollBar = abstractScrollArea.horizontalScrollBar(); + + // On OS X >= 10.9 the scrollbar will be hidden unless explicitly enabled in the preferences + bool scrollBarsVisible = !horizontalScrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, 0, horizontalScrollBar); + int childCount = scrollBarsVisible ? 2 : 1; + QCOMPARE(interface->childCount(), childCount); QWidget *horizontalScrollBarContainer = horizontalScrollBar->parentWidget(); - QVERIFY(verifyChild(horizontalScrollBarContainer, interface, 1, globalGeometry)); + if (scrollBarsVisible) + QVERIFY(verifyChild(horizontalScrollBarContainer, interface, 1, globalGeometry)); // Horizontal scrollBar widgets. QLabel *secondLeftLabel = new QLabel(QLatin1String("L2")); abstractScrollArea.addScrollBarWidget(secondLeftLabel, Qt::AlignLeft); - QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->childCount(), childCount); QLabel *firstLeftLabel = new QLabel(QLatin1String("L1")); abstractScrollArea.addScrollBarWidget(firstLeftLabel, Qt::AlignLeft); - QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->childCount(), childCount); QLabel *secondRightLabel = new QLabel(QLatin1String("R2")); abstractScrollArea.addScrollBarWidget(secondRightLabel, Qt::AlignRight); - QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->childCount(), childCount); QLabel *firstRightLabel = new QLabel(QLatin1String("R1")); abstractScrollArea.addScrollBarWidget(firstRightLabel, Qt::AlignRight); - QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->childCount(), childCount); // Vertical scrollBar. abstractScrollArea.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - QCOMPARE(interface->childCount(), 3); + if (scrollBarsVisible) + ++childCount; + QCOMPARE(interface->childCount(), childCount); QWidget *verticalScrollBar = abstractScrollArea.verticalScrollBar(); QWidget *verticalScrollBarContainer = verticalScrollBar->parentWidget(); - QVERIFY(verifyChild(verticalScrollBarContainer, interface, 2, globalGeometry)); + if (scrollBarsVisible) + QVERIFY(verifyChild(verticalScrollBarContainer, interface, 2, globalGeometry)); // Vertical scrollBar widgets. QLabel *secondTopLabel = new QLabel(QLatin1String("T2")); abstractScrollArea.addScrollBarWidget(secondTopLabel, Qt::AlignTop); - QCOMPARE(interface->childCount(), 3); + QCOMPARE(interface->childCount(), childCount); QLabel *firstTopLabel = new QLabel(QLatin1String("T1")); abstractScrollArea.addScrollBarWidget(firstTopLabel, Qt::AlignTop); - QCOMPARE(interface->childCount(), 3); + QCOMPARE(interface->childCount(), childCount); QLabel *secondBottomLabel = new QLabel(QLatin1String("B2")); abstractScrollArea.addScrollBarWidget(secondBottomLabel, Qt::AlignBottom); - QCOMPARE(interface->childCount(), 3); + QCOMPARE(interface->childCount(), childCount); QLabel *firstBottomLabel = new QLabel(QLatin1String("B1")); abstractScrollArea.addScrollBarWidget(firstBottomLabel, Qt::AlignBottom); - QCOMPARE(interface->childCount(), 3); + QCOMPARE(interface->childCount(), childCount); // CornerWidget. + ++childCount; abstractScrollArea.setCornerWidget(new QLabel(QLatin1String("C"))); - QCOMPARE(interface->childCount(), 4); + QCOMPARE(interface->childCount(), childCount); QWidget *cornerWidget = abstractScrollArea.cornerWidget(); - QVERIFY(verifyChild(cornerWidget, interface, 3, globalGeometry)); + if (scrollBarsVisible) + QVERIFY(verifyChild(cornerWidget, interface, 3, globalGeometry)); QCOMPARE(verifyHierarchy(interface), 0); From 5a4fad14797d7cb0f7a65d5c546a0006475757e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 16 Oct 2014 14:42:50 +0200 Subject: [PATCH 027/323] iOS: Add logging category for input method debugging Change-Id: If1505b3b5f6ceb18fc8972192d637fc42530f993 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosglobal.h | 10 ++++++++++ src/plugins/platforms/ios/qiosglobal.mm | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index c09987f9dc..fccb051645 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -41,6 +41,16 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods); + +#if !defined(QT_NO_DEBUG) +#define qImDebug(...) \ + for (bool qt_category_enabled = lcQpaInputMethods().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \ + QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, lcQpaInputMethods().categoryName()).debug(__VA_ARGS__) +#else +#define qImDebug() QT_NO_QDEBUG_MACRO() +#endif + class QPlatformScreen; bool isQtApplication(); diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 7ff4950599..e6d52f1850 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -46,6 +46,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods"); + bool isQtApplication() { // Returns \c true if the plugin is in full control of the whole application. This means From 50cadb87e8f7f8a9e064c86753f348a1e0f9c485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 16 Oct 2014 15:37:48 +0200 Subject: [PATCH 028/323] iOS: Detect window deactivation without waiting for next runloop iteration Since we know and control whether or not we are making a new QUIView first responder, we can take not of this at that point, and use that information when another view is resigning first responder. Change-Id: I508720d418c92dc8a8011b489cc5cace8fc82633 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosglobal.h | 10 +++++ src/plugins/platforms/ios/qiosglobal.mm | 7 +++ src/plugins/platforms/ios/quiview.mm | 58 +++++++++++++++++-------- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index fccb051645..dbedba7e85 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -71,4 +71,14 @@ QT_END_NAMESPACE +(id)currentFirstResponder; @end +class FirstResponderCandidate : public QScopedValueRollback +{ +public: + FirstResponderCandidate(UIResponder *); + static UIResponder *currentCandidate() { return s_firstResponderCandidate; } + +private: + static UIResponder *s_firstResponderCandidate; +}; + #endif // QIOSGLOBAL_H diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index e6d52f1850..bc16a7997d 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -168,5 +168,12 @@ int infoPlistValue(NSString* key, int defaultValue) } @end +FirstResponderCandidate::FirstResponderCandidate(UIResponder *responder) + : QScopedValueRollback(s_firstResponderCandidate, responder) +{ +} + +UIResponder *FirstResponderCandidate::s_firstResponderCandidate = 0; + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index c46ed4c0b1..33e5b955e3 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -191,33 +191,57 @@ - (BOOL)becomeFirstResponder { - if ([super becomeFirstResponder]) { - QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); - QWindowSystemInterface::flushWindowSystemEvents(); + FirstResponderCandidate firstResponderCandidate(self); - return YES; + qImDebug() << "win:" << m_qioswindow->window() << "self:" << self + << "first:" << [UIResponder currentFirstResponder]; + + if (![super becomeFirstResponder]) { + qImDebug() << m_qioswindow->window() + << "was not allowed to become first responder"; + return NO; } - return NO; + qImDebug() << m_qioswindow->window() << "became first responder"; + + if (qGuiApp->focusWindow() != m_qioswindow->window()) { + QWindowSystemInterface::handleWindowActivated(m_qioswindow->window()); + QWindowSystemInterface::flushWindowSystemEvents(); + } else { + qImDebug() << m_qioswindow->window() + << "already active, not sending window activation"; + } + + return YES; +} + +- (BOOL)responderShouldTriggerWindowDeactivation:(UIResponder *)responder +{ + // We don't want to send window deactivation in case the resign + // was a result of another Qt window becoming first responder. + if ([responder isKindOfClass:[QUIView class]]) + return NO; + + return YES; } - (BOOL)resignFirstResponder { - if ([super resignFirstResponder]) { - // We don't want to send window deactivation in case we're in the process - // of activating another window. The handleWindowActivated of the activation - // will take care of both. - dispatch_async(dispatch_get_main_queue (), ^{ - if (![[UIResponder currentFirstResponder] isKindOfClass:[QUIView class]]) { - QWindowSystemInterface::handleWindowActivated(0); - QWindowSystemInterface::flushWindowSystemEvents(); - } - }); + qImDebug() << "win:" << m_qioswindow->window() << "self:" << self + << "first:" << [UIResponder currentFirstResponder]; - return YES; + if (![super resignFirstResponder]) + return NO; + + qImDebug() << m_qioswindow->window() << "resigned first responder"; + + UIResponder *newResponder = FirstResponderCandidate::currentCandidate(); + if ([self responderShouldTriggerWindowDeactivation:newResponder]) { + QWindowSystemInterface::handleWindowActivated(0); + QWindowSystemInterface::flushWindowSystemEvents(); } - return NO; + return YES; } // ------------------------------------------------------------------------- From 070b183dbc025105f8d9aab44e4d5866686b653c Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Mon, 20 Oct 2014 16:49:31 +0200 Subject: [PATCH 029/323] Doc: removed reference to obsolete classes QSocket and QSocketDevice are not part of Qt 5.4 Task-number: QTBUG-40362 Change-Id: Ieffd992c203af94cac0eb21a630b6ac98754f358 Reviewed-by: Mitch Curtis --- src/corelib/io/qdatastream.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 49526ea2d5..beaafe4762 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -261,12 +261,6 @@ QDataStream::QDataStream() /*! Constructs a data stream that uses the I/O device \a d. - \warning If you use QSocket or QSocketDevice as the I/O device \a d - for reading data, you must make sure that enough data is available - on the socket for the operation to successfully proceed; - QDataStream does not have any means to handle or recover from - short-reads. - \sa setDevice(), device() */ From 148aa0e3e35f9bdf3e68fdf2c9cc509d2e093275 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 28 Oct 2014 14:30:53 +0400 Subject: [PATCH 030/323] Doc: Fix method names for QFileSystemModel There are no methods called name() and path(), replace them by fileName() and filePath(). Task-number: QTBUG-41881 Change-Id: I001a8ead197327fac69e69d94230587ddb1a4692 Reviewed-by: Venugopal Shivashankar --- src/widgets/dialogs/qfilesystemmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp index 988d3ad3c7..baa55cb88f 100644 --- a/src/widgets/dialogs/qfilesystemmodel.cpp +++ b/src/widgets/dialogs/qfilesystemmodel.cpp @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE QFileSystemModel can be accessed using the standard interface provided by QAbstractItemModel, but it also provides some convenience functions that are specific to a directory model. - The fileInfo(), isDir(), name(), and path() functions provide information + The fileInfo(), isDir(), fileName() and filePath() functions provide information about the underlying files and directories related to items in the model. Directories can be created and removed using mkdir(), rmdir(). From 916dfcb8275bcce6b39606cd0b930239a60dc5df Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 28 Oct 2014 11:41:34 +0100 Subject: [PATCH 031/323] OS X - Cocoa backing store and drawRect m_backingStore pointer has a limited 'lifetime' - usually it is set in -flushBackingStore:region:offset: method, then -drawRect: is invoked/forced by -setNeedsDisplayInRect:, after that it's dangerous to have a non-null pointer to a backing store (and we reset it). But if Cocoa invokes drawRect (due to some reason) our null backing store pointer is also not good. This patch instead is using a shared resource (QImage) from a backing store. This patch also makes getBackingStoreCGImage() redundant - -drawRect: was the only place we called it. Task-number: QTBUG-42206 Change-Id: Ie7726336f05d07c52f660f6326ae5cef114201dd Reviewed-by: Gabriel de Dietrich --- .../platforms/cocoa/qcocoabackingstore.h | 5 +---- .../platforms/cocoa/qcocoabackingstore.mm | 13 ----------- src/plugins/platforms/cocoa/qnsview.h | 3 ++- src/plugins/platforms/cocoa/qnsview.mm | 22 +++++++++---------- 4 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index bfff5c3266..917f020132 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -51,12 +51,9 @@ public: QPaintDevice *paintDevice(); void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); -#ifndef QT_NO_OPENGL - QImage toImage() const Q_DECL_OVERRIDE; -#endif + QImage toImage() const; void resize (const QSize &size, const QRegion &); bool scroll(const QRegion &area, int dx, int dy); - CGImageRef getBackingStoreCGImage(); qreal getBackingStoreDevicePixelRatio(); private: diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index e13e295511..ba1198c19c 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -96,12 +96,10 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion ®ion, const QPoint } } -#ifndef QT_NO_OPENGL QImage QCocoaBackingStore::toImage() const { return m_qImage; } -#endif void QCocoaBackingStore::resize(const QSize &size, const QRegion &) { @@ -121,17 +119,6 @@ bool QCocoaBackingStore::scroll(const QRegion &area, int dx, int dy) return true; } -CGImageRef QCocoaBackingStore::getBackingStoreCGImage() -{ - if (!m_cgImage) - m_cgImage = qt_mac_toCGImage(m_qImage); - - // Warning: do not retain/release/cache the returned image from - // outside the backingstore since it shares data with a QImage and - // needs special memory considerations. - return m_cgImage; -} - qreal QCocoaBackingStore::getBackingStoreDevicePixelRatio() { return m_qImage.devicePixelRatio(); diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 8b23f84a25..8d8df13dc3 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -51,7 +51,8 @@ QT_END_NAMESPACE Q_FORWARD_DECLARE_OBJC_CLASS(QNSViewMouseMoveHelper); @interface QT_MANGLE_NAMESPACE(QNSView) : NSView { - QCocoaBackingStore* m_backingStore; + QImage m_backingStore; + qreal m_pixelRatio; QPoint m_backingStoreOffset; CGImageRef m_maskImage; uchar *m_maskData; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 458e0ff924..1f1bc36bf2 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -143,7 +143,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; { self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; if (self) { - m_backingStore = 0; + m_pixelRatio = 1.; m_maskImage = 0; m_shouldInvalidateWindowShadow = false; m_window = 0; @@ -466,8 +466,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset { - m_backingStore = backingStore; - m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio(); + m_backingStore = backingStore->toImage(); + m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio(); + m_backingStoreOffset = offset * m_pixelRatio; foreach (QRect rect, region.rects()) { [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; } @@ -531,7 +532,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (m_platformWindow->m_drawContentBorderGradient) NSDrawWindowBackground(dirtyRect); - if (!m_backingStore) + if (m_backingStore.isNull()) return; // Calculate source and target rects. The target rect is the dirtyRect: @@ -539,11 +540,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; // The backing store source rect will be larger on retina displays. // Scale dirtyRect by the device pixel ratio: - const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio(); - CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio, - dirtyRect.origin.y * devicePixelRatio, - dirtyRect.size.width * devicePixelRatio, - dirtyRect.size.height * devicePixelRatio); + CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio, + dirtyRect.origin.y * m_pixelRatio, + dirtyRect.size.width * m_pixelRatio, + dirtyRect.size.height * m_pixelRatio); NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext]; CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort]; @@ -569,7 +569,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; dirtyBackingRect.size.width, dirtyBackingRect.size.height ); - CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage(); + CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore); CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect); // Optimization: Copy frame buffer content instead of blending for @@ -586,8 +586,6 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; CGImageRelease(subMask); [self invalidateWindowShadowIfNeeded]; - - m_backingStore = 0; } - (BOOL) isFlipped From 3dc4b9ac86968c6a921c546a44c1929ad6684473 Mon Sep 17 00:00:00 2001 From: Steffen Imhof Date: Tue, 17 Jun 2014 09:46:17 +0200 Subject: [PATCH 032/323] Move animation-related header out of QT_NO_IM #ifndef. Change-Id: I7f0bfed4ff9a608575cf6795016b2fa134fd273f Reviewed-by: Marc Mutz --- src/widgets/widgets/qlineedit_p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index a4394ae92b..bafc5352fb 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -55,8 +55,8 @@ #ifndef QT_NO_IM #include "qinputmethod.h" #include "qlist.h" -#include #endif +#include QT_BEGIN_NAMESPACE From 7f8f476244e551b224b56c7f2bff128bc4d873b8 Mon Sep 17 00:00:00 2001 From: Steffen Imhof Date: Tue, 17 Jun 2014 09:51:07 +0200 Subject: [PATCH 033/323] Compile fix for QT_NO_IM in QtWidgets Added some #ifdef guards around usages of composeMode(). Change-Id: If2f2d3cae21b270933b38ea67dcc885f5871785f Reviewed-by: Marc Mutz --- src/widgets/widgets/qlineedit.cpp | 7 ++++++- src/widgets/widgets/qwidgetlinecontrol.cpp | 2 ++ src/widgets/widgets/qwidgetlinecontrol_p.h | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index ba4dbcc878..f1c884e77f 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -1528,13 +1528,16 @@ void QLineEdit::mouseMoveEvent(QMouseEvent * e) #else const bool select = (d->imHints & Qt::ImhNoPredictiveText); #endif +#ifndef QT_NO_IM if (d->control->composeMode() && select) { int startPos = d->xToPos(d->mousePressPos.x()); int currentPos = d->xToPos(e->pos().x()); if (startPos != currentPos) d->control->setSelection(startPos, currentPos - startPos); - } else { + } else +#endif + { d->control->moveCursor(d->xToPos(e->pos().x()), select); } } @@ -1585,6 +1588,7 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) int position = d->xToPos(e->pos().x()); // exit composition mode +#ifndef QT_NO_IM if (d->control->composeMode()) { int preeditPos = d->control->cursor(); int posInPreedit = position - d->control->cursor(); @@ -1609,6 +1613,7 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e) position += (sizeChange - preeditLength); } } +#endif if (position >= 0) d->control->selectWordAtPos(position); diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 75f30599be..e459171e62 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -187,6 +187,7 @@ void QWidgetLineControl::paste(QClipboard::Mode clipboardMode) */ void QWidgetLineControl::commitPreedit() { +#ifndef QT_NO_IM if (!composeMode()) return; @@ -198,6 +199,7 @@ void QWidgetLineControl::commitPreedit() setPreeditArea(-1, QString()); m_textLayout.clearAdditionalFormats(); updateDisplayText(/*force*/ true); +#endif } diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index 1cee67bfd2..5ce1d0ed56 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -221,8 +221,10 @@ public: } void setText(const QString &txt) { +#ifndef QT_NO_IM if (composeMode()) qApp->inputMethod()->reset(); +#endif internalSetText(txt, -1, false); } void commitPreedit(); From fe7c5feb0dece2bc56f0e32668d0193e0f3268c3 Mon Sep 17 00:00:00 2001 From: Volker Krause Date: Sun, 29 Jun 2014 13:25:01 +0200 Subject: [PATCH 034/323] Add missing newline in fallback debug output. This is hit in case of a recursion in the message handler, and message hasn't gone through qMessageFormatString at this point and thus lacks the newline. Change-Id: Ia098b6ccbcc1aff22a4695865f39143ba0152d9c Reviewed-by: Kai Koehne --- src/corelib/global/qlogging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 51169eb963..c47e91e296 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1329,7 +1329,7 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex } ungrabMessageHandler(); } else { - fprintf(stderr, "%s", message.toLocal8Bit().constData()); + fprintf(stderr, "%s\n", message.toLocal8Bit().constData()); } } From 4d5f9df8abe77a8ec1a813b7527c60a422e61946 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 16 Jun 2014 16:50:13 +0200 Subject: [PATCH 035/323] pay attention to the MAKE env variable ... to avoid that inherited MAKEFLAGS turn out to be incompatible with the make we choose. Task-number: QTBUG-39527 Change-Id: I47d4cec58b0643cc5d97868e70b24f7f37e964bb Reviewed-by: Joerg Bornemann --- mkspecs/features/configure.prf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index fe41c541a2..082f983f11 100644 --- a/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -1,4 +1,7 @@ -equals(MAKEFILE_GENERATOR, UNIX) { +QMAKE_MAKE = $$(MAKE) +!isEmpty(QMAKE_MAKE) { + # We were called recursively. Use the right make, as MAKEFLAGS may be set as well. +} else:equals(MAKEFILE_GENERATOR, UNIX) { QMAKE_MAKE = make } else:equals(MAKEFILE_GENERATOR, MINGW) { !equals(QMAKE_HOST.os, Windows): \ From b0098056e565d936b0ce1072ea981bc416751701 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 22 Oct 2014 12:12:26 +0200 Subject: [PATCH 036/323] fix namespaced DirectWrite build Change-Id: Iec6d6ca121b2b04fc1eb4a97f1387ee630e6e1f5 Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowsfontdatabase.h | 4 ++-- .../windows/qwindowsfontenginedirectwrite.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h index a2324544d2..852ab1f8cf 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h @@ -46,13 +46,13 @@ #include #include "qtwindows_additional.h" -QT_BEGIN_NAMESPACE - #if !defined(QT_NO_DIRECTWRITE) struct IDWriteFactory; struct IDWriteGdiInterop; #endif +QT_BEGIN_NAMESPACE + class QWindowsFontEngineData { Q_DISABLE_COPY(QWindowsFontEngineData) diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 2da014ddc3..f033eb635a 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -49,16 +49,16 @@ #include #include -class QWindowsFontEngineData; - -struct IDWriteFont ; -struct IDWriteFontFace ; -struct IDWriteFactory ; -struct IDWriteBitmapRenderTarget ; -struct IDWriteGdiInterop ; +struct IDWriteFont; +struct IDWriteFontFace; +struct IDWriteFactory; +struct IDWriteBitmapRenderTarget; +struct IDWriteGdiInterop; QT_BEGIN_NAMESPACE +class QWindowsFontEngineData; + class QWindowsFontEngineDirectWrite : public QFontEngine { public: From a570e8b0f6b95dbe50e39a183527751aaf6fe562 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Mon, 27 Oct 2014 14:47:25 +0200 Subject: [PATCH 037/323] direct2d: Fix pixmap fills in composition emulation mode When painting a pixmap with rasterFill, the brush should be offset to match the fill path. Change-Id: I4e361932643c4a98dce74e55ed16fae274bce43b Reviewed-by: Louai Al-Khanji --- src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index c13f0f333a..a86bb0ee04 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -1471,7 +1471,8 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, r.x(), r.y() + r.height() }; const QVectorPath vp(points, 4, 0, QVectorPath::RectangleHint); - const QBrush brush(sr.isValid() ? pm.copy(sr.toRect()) : pm); + QBrush brush(sr.isValid() ? pm.copy(sr.toRect()) : pm); + brush.setTransform(QTransform::fromTranslate(r.x(), r.y())); rasterFill(vp, brush); return; } From d6c1a9cb267cc5ffec2e55bc9990ced43c19b73a Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Tue, 28 Oct 2014 09:23:25 +0200 Subject: [PATCH 038/323] direct2d: Fix window resize with translucent windows If the size of the window has changed, the backing bitmap should be reset with the new geometry. Change-Id: I1ca430cd7b5df1845b4fef31f5bf8f05d889a2fc Reviewed-by: Louai Al-Khanji --- .../platforms/direct2d/qwindowsdirect2dwindow.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index ef02d77375..c89d293d1d 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -199,12 +199,13 @@ void QWindowsDirect2DWindow::setupSwapChain() void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) { - if (!m_swapChain) - return; - m_pixmap.reset(); m_bitmap.reset(); m_deviceContext->SetTarget(Q_NULLPTR); + m_needsFullFlush = true; + + if (!m_swapChain) + return; HRESULT hr = m_swapChain->ResizeBuffers(0, size.width(), size.height(), @@ -212,8 +213,6 @@ void QWindowsDirect2DWindow::resizeSwapChain(const QSize &size) 0); if (FAILED(hr)) qWarning("%s: Could not resize swap chain: %#x", __FUNCTION__, hr); - - m_needsFullFlush = true; } QSharedPointer QWindowsDirect2DWindow::copyBackBuffer() const From 6fa2fec1dd3834515b6a898c304ba81b8b91df2f Mon Sep 17 00:00:00 2001 From: MihailNaydenov Date: Fri, 26 Sep 2014 19:42:39 +0300 Subject: [PATCH 039/323] OS X: Fix broken 2x menu icon when style sheet is applied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-41623 Change-Id: I4e0640a7739d0ce4f8758dd5d8d17882a6947467 Reviewed-by: Alessandro Portale Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qstylesheetstyle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 60bfc8e075..8c52b24869 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -3583,8 +3583,8 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode, QIcon::On); else pixmap = mi.icon.pixmap(pixelMetric(PM_SmallIconSize), mode); - int pixw = pixmap.width(); - int pixh = pixmap.height(); + const int pixw = pixmap.width() / pixmap.devicePixelRatio(); + const int pixh = pixmap.height() / pixmap.devicePixelRatio(); QRenderRule iconRule = renderRule(w, opt, PseudoElement_MenuIcon); if (!iconRule.hasGeometry()) { iconRule.geo = new QStyleSheetGeometryData(pixw, pixh, pixw, pixh, -1, -1); From d8f940930e0dbcea4ee136550b4ca5a38f03b1dc Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 20 Oct 2014 14:40:15 +0200 Subject: [PATCH 040/323] vcxproj: fix writing of librarian settings The settings of the librarian were never written. Creation of static libraries only worked by accident. Adapted the code from the vcproj code path. Task-number: QTBUG-30712 Change-Id: I69917f44305eb458647392d222db477fe5a5b7c8 Reviewed-by: Oswald Buddenhagen Reviewed-by: Joerg Bornemann Reviewed-by: Andy Shaw --- qmake/generators/win32/msbuild_objectmodel.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 5fdfc52dba..1ca2c3ae41 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE const char _CLCompile[] = "ClCompile"; const char _ItemGroup[] = "ItemGroup"; const char _Link[] = "Link"; +const char _Lib[] = "Lib"; const char _ManifestTool[] = "ManifestTool"; const char _Midl[] = "Midl"; const char _ResourceCompile[] = "ResourceCompile"; @@ -754,8 +755,11 @@ void VCXProjectWriter::write(XmlOutput &xml, VCProject &tool) // ClCompile write(xml, config.compiler); - // Link - write(xml, config.linker); + // Librarian / Linker + if (config.ConfigurationType == typeStaticLibrary) + write(xml, config.librarian); + else + write(xml, config.linker); // Midl write(xml, config.idl); @@ -1683,7 +1687,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCCustomBuildTool &tool) void VCXProjectWriter::write(XmlOutput &xml, const VCLibrarianTool &tool) { xml - << tag(_Link) + << tag(_Lib) << attrTagX(_AdditionalDependencies, tool.AdditionalDependencies, ";") << attrTagX(_AdditionalLibraryDirectories, tool.AdditionalLibraryDirectories, ";") << attrTagX(_AdditionalOptions, tool.AdditionalOptions, " ") @@ -1703,7 +1707,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCLibrarianTool &tool) //unused << attrTagS(_TargetMachine, tool.TargetMachine) //unused << attrTagT(_TreatLibWarningAsErrors, tool.TreatLibWarningAsErrors) //unused << attrTagT(_Verbose, tool.Verbose) - << closetag(_Link); + << closetag(_Lib); } void VCXProjectWriter::write(XmlOutput &xml, const VCResourceCompilerTool &tool) From a3cb057c3d5c9ed2c12fb7542065c3d667be38b7 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Mon, 22 Sep 2014 12:35:22 +0400 Subject: [PATCH 041/323] Doc: Don't show a description for omitted SH_ComboBox_UseNativePopup enum item \omitvalue does not allow a description of an enum item, so move the description as a comment to the enum declaration. Change-Id: I4192b16e41b704cbad66c0eeafcb141087d2ba65 Reviewed-by: Martin Smith --- src/widgets/styles/qstyle.cpp | 3 +-- src/widgets/styles/qstyle.h | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp index 4c5c7cd17e..c4854f2925 100644 --- a/src/widgets/styles/qstyle.cpp +++ b/src/widgets/styles/qstyle.cpp @@ -1750,8 +1750,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, \value SH_ComboBox_Popup Allows popups as a combobox drop-down menu. - \omitvalue SH_ComboBox_UseNativePopup Whether we should use a native popup. - Only supported for non-editable combo boxes on Mac OS X so far. + \omitvalue SH_ComboBox_UseNativePopup \value SH_Workspace_FillSpaceOnMaximize The workspace should maximize the client area. diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h index 136daa9abd..9c9493041f 100644 --- a/src/widgets/styles/qstyle.h +++ b/src/widgets/styles/qstyle.h @@ -702,6 +702,8 @@ public: SH_ToolTip_FallAsleepDelay, SH_Widget_Animate, SH_Splitter_OpaqueResize, + // Whether we should use a native popup. + // Only supported for non-editable combo boxes on Mac OS X so far. SH_ComboBox_UseNativePopup, // Add new style hint values here From 25948f83b4b0cafe5f6c34cb842181ee52d8480d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Oct 2014 10:21:01 +0100 Subject: [PATCH 042/323] iOS: Make a few member variables of QIOSTextInputResponder private MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I269b1b5ab802c391a12bcdc8cfe0c4d3e52f9cba Reviewed-by: Richard Moe Gustavsen Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiostextresponder.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/ios/qiostextresponder.h b/src/plugins/platforms/ios/qiostextresponder.h index 2923feba3b..118ab8958a 100644 --- a/src/plugins/platforms/ios/qiostextresponder.h +++ b/src/plugins/platforms/ios/qiostextresponder.h @@ -47,12 +47,10 @@ class QIOSInputContext; @interface QIOSTextInputResponder : UIResponder { - @public - QString m_markedText; - BOOL m_inSendEventToFocusObject; - @private QIOSInputContext *m_inputContext; + QString m_markedText; + BOOL m_inSendEventToFocusObject; } - (id)initWithInputContext:(QIOSInputContext *)context; From 80d31849e258d8105e9ac1558023e10b6514fdd3 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 28 Oct 2014 15:15:41 +0200 Subject: [PATCH 043/323] Fix indentation & coding style. Change-Id: Id974abca3ee2be9cb70c380a842e76c0ba1520bd Reviewed-by: Oswald Buddenhagen --- src/network/socket/qlocalserver_unix.cpp | 36 ++++++++++++------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index 149d89c000..a5ae363540 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -160,30 +160,30 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) } if (socketOptions & QLocalServer::WorldAccessOption) { - mode_t mode = 000; + mode_t mode = 000; - if (socketOptions & QLocalServer::UserAccessOption) { - mode |= S_IRWXU; - } - if (socketOptions & QLocalServer::GroupAccessOption) { - mode |= S_IRWXG; - } - if (socketOptions & QLocalServer::OtherAccessOption) { - mode |= S_IRWXO; - } + if (socketOptions & QLocalServer::UserAccessOption) + mode |= S_IRWXU; - if (mode) { - if (-1 == ::chmod(tempPath.toLatin1(), mode)) { - setError(QLatin1String("QLocalServer::listen")); - closeServer(); - return false; - } - } - if (-1 == ::rename(tempPath.toLatin1(), fullServerName.toLatin1())){ + if (socketOptions & QLocalServer::GroupAccessOption) + mode |= S_IRWXG; + + if (socketOptions & QLocalServer::OtherAccessOption) + mode |= S_IRWXO; + + if (mode) { + if (::chmod(tempPath.toLatin1(), mode) == -1) { setError(QLatin1String("QLocalServer::listen")); closeServer(); return false; } + } + + if (::rename(tempPath.toLatin1(), fullServerName.toLatin1()) == -1) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } } Q_ASSERT(!socketNotifier); From 4b8d4034d7d62c1e2022619d5cff60174d244770 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 28 Oct 2014 15:16:55 +0200 Subject: [PATCH 044/323] Removed pointless conditional. Mode is always != 0 at this point (QLocalServer::WorldAccessOption is a combination of the bits tested later). Change-Id: I5abfb4e49fdc7903e21398525af05989f40d7f94 Reviewed-by: Oswald Buddenhagen Reviewed-by: BogDan Vatra --- src/network/socket/qlocalserver_unix.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index a5ae363540..1e5a4e98ee 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -171,12 +171,10 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) if (socketOptions & QLocalServer::OtherAccessOption) mode |= S_IRWXO; - if (mode) { - if (::chmod(tempPath.toLatin1(), mode) == -1) { - setError(QLatin1String("QLocalServer::listen")); - closeServer(); - return false; - } + if (::chmod(tempPath.toLatin1(), mode) == -1) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; } if (::rename(tempPath.toLatin1(), fullServerName.toLatin1()) == -1) { From aa4d76e468512d34b690c08b803c36a4bfc4a3bf Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 28 Oct 2014 15:23:37 +0200 Subject: [PATCH 045/323] Remove redundant permission set. The temp socket is in a safe place. There is no need to set any permissions at this point. Change-Id: I18ea4b71b7c20db65dc46c57ddc5d34d8b93f577 Reviewed-by: Oswald Buddenhagen --- src/network/socket/qlocalserver_unix.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index 1e5a4e98ee..313fe4ad29 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -124,13 +124,6 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) } ::memcpy(addr.sun_path, tempPath.toLatin1().data(), tempPath.toLatin1().size() + 1); - - if (-1 == ::fchmod(listenSocket, 0)) { - setError(QLatin1String("QLocalServer::listen")); - closeServer(); - return false; - } - } else { ::memcpy(addr.sun_path, fullServerName.toLatin1().data(), fullServerName.toLatin1().size() + 1); From 7567e09389fffdf8901aed6501744dd0fcf4a72d Mon Sep 17 00:00:00 2001 From: Jerome Pasion Date: Sun, 19 Oct 2014 18:33:11 +0200 Subject: [PATCH 046/323] Doc: Updated thumbnail images for some examples. -Application Example -Analog Clock -Analog Clock Window -Scribble -Digital Clock -Thumbnail images were created with an obscure window manager and they look out of place in the Welcome Mode in Qt Creator. -Used Windows 7 as the platform. -Images within the documentation not updated because they are still relevant. Task-number: QTBUG-33597 Change-Id: I255fc4960e9adcec273f21287ef2182656c6b007 Reviewed-by: Venugopal Shivashankar Reviewed-by: Jerome Pasion --- doc/src/images/analogclock-example.png | Bin 2383 -> 14556 bytes doc/src/images/application.png | Bin 26272 -> 19503 bytes doc/src/images/digitalclock-example.png | Bin 6142 -> 6603 bytes doc/src/images/scribble-example.png | Bin 9053 -> 19910 bytes .../doc/images/analogclock-window-example.png | Bin 2383 -> 14556 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/src/images/analogclock-example.png b/doc/src/images/analogclock-example.png index ffd7baa7169ac41182c8de438ac95e2014b4d824..b195f8bf24b2a85b33afb95e25b69432849eb919 100644 GIT binary patch literal 14556 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 XSJc_!x8o20_0be%Rb{H*nT7lp`Qast diff --git a/doc/src/images/scribble-example.png b/doc/src/images/scribble-example.png index a2cb1de3e8461cb36e42da47cd90746b30ab765a..54091baa6b7110058b5f54dfd54a34a4e9bb1585 100644 GIT binary patch literal 19910 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 literal 9053 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 g_nlqT9F)Ww4#UJF*}FfyQW9us{yv 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 literal 2383 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 Date: Tue, 28 Oct 2014 14:33:39 +0100 Subject: [PATCH 047/323] moc: do not error if the last token of a define is # MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do not need to emit a diagnostic at definition time. The diagnostic will be emit at expansion time. Fix error when parsing boost header: /usr/include/boost/fusion/container/vector/vector.hpp:25: Error: '#' is not followed by a macro parameter Task-number: QTBUG-42233 Change-Id: I27deab362341f17ca3b0160615bb1b0934c3d5c3 Reviewed-by: Jędrzej Nowacki --- src/tools/moc/preprocessor.cpp | 6 +----- tests/auto/tools/moc/parse-defines.h | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index 087b064c0f..c5d6b58412 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Copyright (C) 2013 Olivier Goffart +** Copyright (C) 2014 Olivier Goffart ** Contact: http://www.qt-project.org/legal ** ** This file is part of the tools applications of the Qt Toolkit. @@ -1094,10 +1094,6 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) macro.symbols.last().token == PP_HASHHASH) { error("'##' cannot appear at either end of a macro expansion"); } - if (macro.symbols.last().token == HASH || - macro.symbols.last().token == PP_HASH) { - error("'#' is not followed by a macro parameter"); - } } macros.insert(name, macro); continue; diff --git a/tests/auto/tools/moc/parse-defines.h b/tests/auto/tools/moc/parse-defines.h index c9b5d13b1f..9a00955846 100644 --- a/tests/auto/tools/moc/parse-defines.h +++ b/tests/auto/tools/moc/parse-defines.h @@ -77,6 +77,8 @@ #define DEFINE_CMDLINE_SIGNAL void cmdlineSignal(const QMap &i) #endif +#define HASH_SIGN # + PD_BEGIN_NAMESPACE class DEFINE_CMDLINE_EMPTY PD_CLASSNAME DEFINE_CMDLINE_EMPTY From a8ed001f36d1635bef3eb6a1bf5adcfae65dafd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 24 Oct 2014 17:43:18 +0200 Subject: [PATCH 048/323] iOS: Properly detect arm64 builds when choosing which -arch flags to pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ib410584ba2c1fe342efb18eb955273090d36db8f Reviewed-by: Oswald Buddenhagen Reviewed-by: Simon Hausmann Reviewed-by: Tor Arne Vestbø --- mkspecs/macx-ios-clang/features/default_post.prf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 79024c588c..2001f53ec4 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -195,8 +195,8 @@ macx-xcode { QMAKE_MAC_XCODE_SETTINGS += arch_iphoneos arch_iphonesimulator unset(QMAKE_XCODE_ARCHS) } else { -# Be more specific about which architecture we're targeting - equals(QT_ARCH, arm): \ + # Be more specific about which architecture we're targeting + contains(QT_ARCH, arm.*): \ actual_archs = $$QMAKE_IOS_DEVICE_ARCHS else: \ actual_archs = $$QMAKE_IOS_SIMULATOR_ARCHS From b1d3f1fec0d5c9f4f950f1d16ba25791fdcc8951 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Sun, 26 Oct 2014 10:03:48 +1000 Subject: [PATCH 049/323] QtBearer corewlan add list of remembered networks These should be at least Defined by the system even with wifi power off Change-Id: I0964ba82fe3fab98585ea7771687cef4d1b70cf9 Reviewed-by: Alex Blasche --- .../bearer/corewlan/qcorewlanengine.mm | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/plugins/bearer/corewlan/qcorewlanengine.mm b/src/plugins/bearer/corewlan/qcorewlanengine.mm index 6f9ea91799..55847a04a4 100644 --- a/src/plugins/bearer/corewlan/qcorewlanengine.mm +++ b/src/plugins/bearer/corewlan/qcorewlanengine.mm @@ -288,8 +288,6 @@ void QScanThread::getUserConfigurations() for (NSString *ifName in wifiInterfaces) { CWInterface *wifiInterface = [CWInterface interfaceWithName: ifName]; - if (!wifiInterface.powerOn) - continue; NSString *nsInterfaceName = wifiInterface.ssid; // add user configured system networks @@ -311,6 +309,21 @@ void QScanThread::getUserConfigurations() CFRelease(airportPlist); } + // remembered networks + CWConfiguration *userConfig = [wifiInterface configuration]; + NSOrderedSet *networkProfiles = [userConfig networkProfiles]; + NSEnumerator *enumerator = [networkProfiles objectEnumerator]; + CWNetworkProfile *wProfile; + while ((wProfile = [enumerator nextObject])) { + QString networkName = QCFString::toQString([wProfile ssid]); + + if (!userProfiles.contains(networkName)) { + QMap map; + map.insert(networkName, QCFString::toQString(nsInterfaceName)); + userProfiles.insert(networkName, map); + } + } + // 802.1X user profiles QString userProfilePath = QDir::homePath() + "/Library/Preferences/com.apple.eap.profiles.plist"; NSDictionary* eapDict = [[[NSDictionary alloc] initWithContentsOfFile: QCFString::toNSString(userProfilePath)] autorelease]; @@ -330,14 +343,14 @@ void QScanThread::getUserConfigurations() [itemKey getObjects:objects andKeys:keys]; QString networkName; QString ssid; - for(int i = 0; i < dictSize; i++) { + for (int i = 0; i < dictSize; i++) { if([nameStr isEqualToString:keys[i]]) { networkName = QCFString::toQString(objects[i]); } - if([networkSsidStr isEqualToString:keys[i]]) { + if ([networkSsidStr isEqualToString:keys[i]]) { ssid = QCFString::toQString(objects[i]); } - if(!userProfiles.contains(networkName) + if (!userProfiles.contains(networkName) && !ssid.isEmpty()) { QMap map; map.insert(ssid, QCFString::toQString(nsInterfaceName)); From 23553cccdaf42189fe2390f9b8082828fb1a5237 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 28 Oct 2014 12:36:45 +0100 Subject: [PATCH 050/323] Fix justification in multi fontengine glyphruns QTextLine::glyphRuns was not handling justification when splitting glyphRuns due to multiple font-engines. This patch adds the missing justification. Task-number: QTBUG-41901 Change-Id: I02d24218630506da21531a6499784dff2eecdf6f Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextlayout.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 911d1b8bc7..1ac50d3e5c 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -2256,8 +2256,10 @@ QList QTextLine::glyphRuns(int from, int length) const logClusters, iterator.itemStart, iterator.itemLength)); - for (int i = 0; i < subLayout.numGlyphs; ++i) - pos.rx() += subLayout.advances[i].toReal(); + for (int i = 0; i < subLayout.numGlyphs; ++i) { + QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6); + pos.rx() += (subLayout.advances[i] + justification).toReal(); + } if (rtl) end = start; From 320360131559df76ba1f635b665659f57e147665 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 28 Oct 2014 13:53:14 +0200 Subject: [PATCH 051/323] Fix QLocalServer, create a temp path as small as possible. If requestedServerName is a full path e.g. "/tmp/some/long/path" the temp path will end up "/tmp/some/long/path.balblabla/tmp/some/long/path" and it might fail because it doesn't fit in addr.sun_path. Change-Id: I6a138fd92be9e0b3b432ab9ac977d04cb330f3fd Reviewed-by: Oswald Buddenhagen --- src/network/socket/qlocalserver_unix.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index 313fe4ad29..a615dcc7b6 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -90,13 +90,14 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) // Check any of the flags if (socketOptions & QLocalServer::WorldAccessOption) { - tempDir.reset(new QTemporaryDir(fullServerName)); + QFileInfo serverNameFileInfo(fullServerName); + tempDir.reset(new QTemporaryDir(serverNameFileInfo.absolutePath() + QLatin1Char('/'))); if (!tempDir->isValid()) { setError(QLatin1String("QLocalServer::listen")); return false; } tempPath = tempDir->path(); - tempPath += QLatin1Char('/') + requestedServerName; + tempPath += QLatin1String("/s"); } // create the unix socket From ad1ec8b57dde6f5cbb7a4f66272794a067dc3917 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Tue, 28 Oct 2014 16:10:57 +0400 Subject: [PATCH 052/323] xcb: Fix setting the alert state for a window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Send a _NET_WM_STATE client message to the root window instead of changing the window property. Task-number: QTBUG-41310 Change-Id: I864af0158ec55796bb3cbc123469709b2be54ec8 Reviewed-by: Martin Gräßlin Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbwindow.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0c2e9d047c..5d3206b097 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2380,13 +2380,10 @@ void QXcbWindow::setAlertState(bool enabled) { if (m_alertState == enabled) return; - const NetWmStates oldState = netWmStates(); + m_alertState = enabled; - if (enabled) { - setNetWmStates(oldState | NetWmStateDemandsAttention); - } else { - setNetWmStates(oldState & ~NetWmStateDemandsAttention); - } + + changeNetWmState(enabled, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)); } bool QXcbWindow::needsSync() const From 38c2e3d1049f494529cb9876bcd564ec20ba512c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 1 Sep 2014 14:26:51 +0200 Subject: [PATCH 053/323] Properly detect UTF-8 BOM markers in ini files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we detect a utf8 BOM mark at the beginning of the .ini file, skip the marker and set the iniCodec to utf8. Task-number: QTBUG-23381 Change-Id: I1b37fc4f1638a48e4f3ee71ab165e2989bc592f1 Reviewed-by: Jędrzej Nowacki --- src/corelib/io/qsettings.cpp | 9 +++++++++ src/corelib/io/qsettings_p.h | 2 +- tests/auto/corelib/io/qsettings/bom.ini | 4 ++++ tests/auto/corelib/io/qsettings/qsettings.qrc | 17 +++++++++-------- .../auto/corelib/io/qsettings/tst_qsettings.cpp | 10 ++++++++++ 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 tests/auto/corelib/io/qsettings/bom.ini diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index d896da176a..ebca7d57ff 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1637,6 +1637,15 @@ bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data, int sectionPosition = 0; bool ok = true; +#ifndef QT_NO_TEXTCODEC + // detect utf8 BOM + const uchar *dd = (const uchar *)data.constData(); + if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf) { + iniCodec = QTextCodec::codecForName("UTF-8"); + dataPos = 3; + } +#endif + while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) { char ch = data.at(lineStart); if (ch == '[') { diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h index cb29b4c83a..715f13530a 100644 --- a/src/corelib/io/qsettings_p.h +++ b/src/corelib/io/qsettings_p.h @@ -282,7 +282,7 @@ public: bool isWritable() const; QString fileName() const; - static bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections); + bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections); static bool readIniSection(const QSettingsKey §ion, const QByteArray &data, ParsedSettingsMap *settingsMap, QTextCodec *codec); static bool readIniLine(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen, diff --git a/tests/auto/corelib/io/qsettings/bom.ini b/tests/auto/corelib/io/qsettings/bom.ini new file mode 100644 index 0000000000..8d46ee8d91 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/bom.ini @@ -0,0 +1,4 @@ +[section1] +foo1=bar1 +[section2] +foo2=bar2 diff --git a/tests/auto/corelib/io/qsettings/qsettings.qrc b/tests/auto/corelib/io/qsettings/qsettings.qrc index 587c22ebe3..c0be7e013f 100644 --- a/tests/auto/corelib/io/qsettings/qsettings.qrc +++ b/tests/auto/corelib/io/qsettings/qsettings.qrc @@ -1,9 +1,10 @@ - - - resourcefile.ini - resourcefile2.ini - resourcefile3.ini - resourcefile4.ini - resourcefile5.ini - + + + resourcefile.ini + resourcefile2.ini + resourcefile3.ini + resourcefile4.ini + resourcefile5.ini + bom.ini + diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp index 3e68e4859f..c89923f159 100644 --- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp +++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp @@ -161,6 +161,7 @@ private slots: void testByteArray_data(); void testByteArray(); void iniCodec(); + void bom(); private: const bool m_canWriteNativeSystemSettings; @@ -730,6 +731,15 @@ void tst_QSettings::iniCodec() } +void tst_QSettings::bom() +{ + QSettings s(":/bom.ini", QSettings::IniFormat); + QStringList allkeys = s.allKeys(); + QCOMPARE(allkeys.size(), 2); + QVERIFY(allkeys.contains("section1/foo1")); + QVERIFY(allkeys.contains("section2/foo2")); +} + void tst_QSettings::testErrorHandling_data() { QTest::addColumn("filePerms"); // -1 means file should not exist From 11e09a440b9b4e80878dc685f9d49d8a43ff6604 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 20 Oct 2014 21:21:12 +0200 Subject: [PATCH 054/323] tst_qvariant: automate testing of forward_list ...using the SD-6 __has_include macro. Change-Id: I629e2ad1c8090aba9e86ab9febf6d09a504219f9 Reviewed-by: Olivier Goffart --- tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 4264c96745..41a6de214a 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -3798,11 +3798,10 @@ struct ContainerAPI } }; -// We have no built-in defines to check the stdlib features. -// #define TEST_FORWARD_LIST - -#ifdef TEST_FORWARD_LIST -#include +#ifdef __has_include +# if __has_include() +# define TEST_FORWARD_LIST +# include Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(std::forward_list) @@ -3856,7 +3855,8 @@ struct ContainerAPI > return variant == value; } }; -#endif +# endif // __has_include() +#endif // __has_include template struct KeyGetter From a0bdbc144299be3b77ceafdd28b23bf0e041a657 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 27 Oct 2014 17:04:37 +0100 Subject: [PATCH 055/323] Fix QWidget::scroll during painting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling scroll during painting fails in cases where the scroll is attempted accelerated. This is easily fixed by not using accelerated scrolling during painting. Task-number: QTBUG-41615 Change-Id: I38d2428d5679c242f13d53793a3dc3b8e01b538f Reviewed-by: Jørgen Lind --- src/widgets/kernel/qwidgetbackingstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 00052c868f..9f014aa4fe 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -869,7 +869,7 @@ void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy) QRect scrollRect = rect & clipRect(); bool overlapped = false; - bool accelerateScroll = accelEnv && isOpaque + bool accelerateScroll = accelEnv && isOpaque && !q_func()->testAttribute(Qt::WA_WState_InPaintEvent) && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft()))); if (!accelerateScroll) { From 7ebc151bcfe71dc837ce9fb2d4c71b7cba7bb7f0 Mon Sep 17 00:00:00 2001 From: Bjoern Breitmeyer Date: Thu, 4 Sep 2014 11:25:20 +0200 Subject: [PATCH 056/323] Fix X86 Wince builds. Windows CE does not have all _BitScanReverse intrinsics, so disable those for Q_OS_WINCE. Change-Id: I34a3c02c6ffdfff2a209b2c9c1b80bef4566ee39 Reviewed-by: Friedemann Kleint --- src/3rdparty/pcre/sljit/sljitNativeX86_common.c | 4 +++- src/corelib/tools/qsimd_p.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c index 653705f6ca..9a2726c935 100644 --- a/src/3rdparty/pcre/sljit/sljitNativeX86_common.c +++ b/src/3rdparty/pcre/sljit/sljitNativeX86_common.c @@ -276,7 +276,9 @@ static sljit_si cpu_has_sse2 = -1; #endif static sljit_si cpu_has_cmov = -1; -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#ifdef _WIN32_WCE +#include +#elif defined(_MSC_VER) && _MSC_VER >= 1400 #include #endif diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index ee2ff99a80..434819aa61 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -318,7 +318,7 @@ static inline uint qCpuFeatures() #ifdef Q_PROCESSOR_X86 // Bit scan functions for x86 -# ifdef Q_CC_MSVC +# if defined(Q_CC_MSVC) && !defined(Q_OS_WINCE) // MSVC calls it _BitScanReverse and returns the carry flag, which we don't need static __forceinline unsigned long _bit_scan_reverse(uint val) { From e1ff27ca28e8a7ab5b0425e8b5d7dd671e59b407 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 13 Oct 2014 14:47:13 +0200 Subject: [PATCH 057/323] add support for explicitly declaring the module master header when a module delegates to another module (as the activeqt ones do), it doesn't have a master header to be included. we could derive the real master header by doing a transitive dependency resolution and some filtering, but that seems unnecessarily complex. Task-number: QTBUG-41892 Change-Id: Ie7ce51a837ac06e929b204ec734206c11b3ae241 Reviewed-by: Friedemann Kleint Reviewed-by: Joerg Bornemann --- mkspecs/features/qt_module_headers.prf | 4 +++- mkspecs/features/qt_module_pris.prf | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/qt_module_headers.prf b/mkspecs/features/qt_module_headers.prf index baeb22d9b4..5015d58861 100644 --- a/mkspecs/features/qt_module_headers.prf +++ b/mkspecs/features/qt_module_headers.prf @@ -58,7 +58,9 @@ MODULE_MASTER_DEPS_HEADER = $$MODULE_BASE_OUTDIR/include/$$MODULE_INCNAME/$${MOD MODULE_MASTER_DEPS_HEADER_CONT = $$autogen_warning MODULE_MASTER_DEPS_HEADER_CONT += "$${LITERAL_HASH}ifdef __cplusplus /* create empty PCH in C mode */" for(dep, MODULE_DEPENDS) { - depname = $$eval(QT.$${dep}.name) + depname = $$eval(QT.$${dep}.master_header) + isEmpty(depname): \ + depname = $$eval(QT.$${dep}.name) MODULE_MASTER_DEPS_HEADER_CONT += "$${LITERAL_HASH}include <$$depname/$$depname>" } MODULE_MASTER_DEPS_HEADER_CONT += "$${LITERAL_HASH}endif" diff --git a/mkspecs/features/qt_module_pris.prf b/mkspecs/features/qt_module_pris.prf index 3d438e52f4..9a876caf5e 100644 --- a/mkspecs/features/qt_module_pris.prf +++ b/mkspecs/features/qt_module_pris.prf @@ -74,6 +74,10 @@ MODULE_FWD_PRI = $$mod_work_pfx/qt_lib_$${MODULE_ID}.pri module_plugtypes = "QT.$${MODULE_ID}.plugin_types = $$replace(MODULE_PLUGIN_TYPES, /.*$, )" else: \ module_plugtypes = + !isEmpty(MODULE_MASTER_HEADER): \ + module_master = "QT.$${MODULE_ID}.master_header = $$MODULE_MASTER_HEADER" + else: \ + module_master = !no_module_headers:!minimal_syncqt { MODULE_INCLUDES = \$\$QT_MODULE_INCLUDE_BASE \$\$QT_MODULE_INCLUDE_BASE/$$MODULE_INCNAME MODULE_PRIVATE_INCLUDES = \$\$QT_MODULE_INCLUDE_BASE/$$MODULE_INCNAME/$$VERSION \ @@ -97,6 +101,7 @@ MODULE_FWD_PRI = $$mod_work_pfx/qt_lib_$${MODULE_ID}.pri "QT.$${MODULE_ID}.name = $$TARGET" \ "QT.$${MODULE_ID}.libs = $$module_libs" \ $$module_rpath \ + $$module_master \ "QT.$${MODULE_ID}.includes = $$MODULE_INCLUDES" !host_build: MODULE_PRI_CONT += \ "QT.$${MODULE_ID}.bins = \$\$QT_MODULE_BIN_BASE" \ From 87eb3ea1904756362ce5474838b25b5b00193dc5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 20 Oct 2014 20:43:48 +0200 Subject: [PATCH 058/323] work around MSVC2010 ICE Task-number: QTBUG-42064 Change-Id: Ifffcc0cf9109b76d79f603a13792d7fd9979761c Reviewed-by: Joerg Bornemann --- qmake/library/proitems.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qmake/library/proitems.cpp b/qmake/library/proitems.cpp index e4dc840b22..97cc590d84 100644 --- a/qmake/library/proitems.cpp +++ b/qmake/library/proitems.cpp @@ -416,8 +416,8 @@ QStringList ProStringList::toQStringList() const { QStringList ret; ret.reserve(size()); - foreach (const ProString &str, *this) - ret << str.toQString(); + for (int i = 0; i < size(); i++) // foreach causes MSVC2010 ICE + ret << at(i).toQString(); return ret; } From 14e51127cf2ba4fdb3469da90fd2f8f26084bb4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 23 Oct 2014 13:58:08 +0200 Subject: [PATCH 059/323] Add qobject_cast template specialisation for QWindow greatly improving the performance of qobject_cast Change-Id: If5a1afa6e41f4676f4838ea3ff80f1d89e396dfc Reviewed-by: Gunnar Sletta --- src/gui/kernel/qwindow.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 7cd25b010f..473d275b56 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -356,6 +356,19 @@ private: friend Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window); }; +#ifndef Q_QDOC +template <> inline QWindow *qobject_cast(QObject *o) +{ + if (!o || !o->isWindowType()) return 0; + return static_cast(o); +} +template <> inline const QWindow *qobject_cast(const QObject *o) +{ + if (!o || !o->isWindowType()) return 0; + return static_cast(o); +} +#endif // !Q_QDOC + QT_END_NAMESPACE #endif // QWINDOW_H From 6c38a82aa8165bbe3cbdc7f17e67999439842c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 23 Oct 2014 16:02:31 +0200 Subject: [PATCH 060/323] Cocoa: Send obscure events on OcclusionStateHidden This disables animations for windows that are completely obscured by other windows. On examples/quick/animation, obscured CPU usage goes from 10% to 1%. There has been reports of 100% CPU usage with Qt before this patch. Change-Id: Iefea43ed8c1cfaa2df13f1f5a4e4450146ade522 Reviewed-by: Laszlo Agocs Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qnsview.mm | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 1f1bc36bf2..1fb30567bc 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -420,12 +420,17 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; #pragma clang diagnostic ignored "-Wobjc-method-access" enum { NSWindowOcclusionStateVisible = 1UL << 1 }; #endif - // Older versions managed in -[QNSView viewDidMoveToWindow]. - // Support QWidgetAction in NSMenu. Mavericks only sends this notification. - // Ideally we should support this in Qt as well, in order to disable animations - // when the window is occluded. - if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) + if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) { m_platformWindow->exposeWindow(); + } else { + // Send Obscure events on window occlusion to stop animations. Several + // unit tests expect paint and/or expose events for windows that are + // sometimes (unpredictably) occlouded: Don't send Obscure events when + // running under QTestLib. + static bool onTestLib = qt_mac_resolveOption(false, "QT_QTESTLIB_RUNNING"); + if (!onTestLib) + m_platformWindow->obscureWindow(); + } #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 #pragma clang diagnostic pop #endif From 100ed0c01d7678a97e3b7b3a46320d84b3a7096d Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 24 Sep 2014 18:14:22 +0400 Subject: [PATCH 061/323] xcb: Fix getting the primary screen from QXcbConnection::screens() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently getting QXcbScreen* for primary screen is too messy and it wrongly uses QXcbConnection::primaryScreen() as an index in QXcbConnection::screens() although QXcbConnection::screens() returns the primary screen as the first item in the list since 3c8eb404877df9c967d81fa9df7d718c538fb407. So to clear the API rename primaryScreen() to primaryScreenNumber(), add QXcbConnection::primaryScreen() that returns correct QXcbScreen* and use it directly. Change-Id: Icb7391aa3e82b32ca48f2bda764dcf7ffd89cc47 Reviewed-by: Uli Schlachter Reviewed-by: Jørgen Lind --- src/plugins/platforms/xcb/qxcbclipboard.cpp | 2 +- src/plugins/platforms/xcb/qxcbconnection.cpp | 20 ++++++++++++++----- src/plugins/platforms/xcb/qxcbconnection.h | 5 +++-- src/plugins/platforms/xcb/qxcbdrag.cpp | 2 +- src/plugins/platforms/xcb/qxcbintegration.cpp | 4 +--- .../platforms/xcb/qxcbnativeinterface.cpp | 2 +- .../platforms/xcb/qxcbsystemtraytracker.cpp | 7 ++----- src/plugins/platforms/xcb/qxcbwmsupport.cpp | 4 ++-- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index 45856f3e6c..8b3893ec2f 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -276,7 +276,7 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c) m_timestamp[QClipboard::Clipboard] = XCB_CURRENT_TIME; m_timestamp[QClipboard::Selection] = XCB_CURRENT_TIME; - m_screen = connection()->screens().at(connection()->primaryScreen()); + m_screen = connection()->primaryScreen(); int x = 0, y = 0, w = 3, h = 3; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 835c414d85..5510c3b1b4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -244,7 +244,7 @@ void QXcbConnection::updateScreens() // the first or an exact match. An exact match isn't // always available if primary->output is XCB_NONE // or currently disconnected output. - if (m_primaryScreen == xcbScreenNumber) { + if (m_primaryScreenNumber == xcbScreenNumber) { if (!primaryScreen || (primary && outputs[i] == primary->output)) { primaryScreen = screen; siblings.prepend(siblings.takeLast()); @@ -306,7 +306,7 @@ void QXcbConnection::updateScreens() QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, const char *displayName) : m_connection(0) , m_canGrabServer(canGrabServer) - , m_primaryScreen(0) + , m_primaryScreenNumber(0) , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) , m_nativeInterface(nativeInterface) , xfixes_first_event(0) @@ -331,7 +331,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra #ifdef XCB_USE_XLIB dpy = XOpenDisplay(m_displayName.constData()); if (dpy) { - m_primaryScreen = DefaultScreen(dpy); + m_primaryScreenNumber = DefaultScreen(dpy); m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); @@ -339,7 +339,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_xlib_display = dpy; } #else - m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen); + m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); #endif //XCB_USE_XLIB if (!m_connection || xcb_connection_has_error(m_connection)) @@ -449,6 +449,16 @@ QXcbConnection::~QXcbConnection() delete m_keyboard; } +QXcbScreen *QXcbConnection::primaryScreen() const +{ + if (!m_screens.isEmpty()) { + Q_ASSERT(m_screens.first()->screenNumber() == primaryScreenNumber()); + return m_screens.first(); + } + + return Q_NULLPTR; +} + void QXcbConnection::addWindowEventListener(xcb_window_t id, QXcbWindowEventListener *eventListener) { m_mapper.insert(id, eventListener); @@ -1219,7 +1229,7 @@ xcb_timestamp_t QXcbConnection::getTimestamp() xcb_window_t QXcbConnection::rootWindow() { - return screens().at(primaryScreen())->root(); + return primaryScreen()->root(); } void QXcbConnection::processXcbEvents() diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 4a16e116c6..51c7c91bf6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -369,7 +369,8 @@ public: QXcbConnection *connection() const { return const_cast(this); } const QList &screens() const { return m_screens; } - int primaryScreen() const { return m_primaryScreen; } + int primaryScreenNumber() const { return m_primaryScreenNumber; } + QXcbScreen *primaryScreen() const; inline xcb_atom_t atom(QXcbAtom::Atom atom) const { return m_allAtoms[atom]; } QXcbAtom::Atom qatom(xcb_atom_t atom) const; @@ -550,7 +551,7 @@ private: bool m_canGrabServer; QList m_screens; - int m_primaryScreen; + int m_primaryScreenNumber; xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 53437f24ae..7037e102e2 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -311,7 +311,7 @@ void QXcbDrag::move(const QMouseEvent *me) return; const QList &screens = connection()->screens(); - QXcbScreen *screen = screens.at(connection()->primaryScreen()); + QXcbScreen *screen = connection()->primaryScreen(); for (int i = 0; i < screens.size(); ++i) { if (screens.at(i)->geometry().contains(globalPos)) { screen = screens.at(i); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index d3533b8e44..52269bafea 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -417,10 +417,8 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::StartDragDistance: { // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. - const QList &screens = defaultConnection()->screens(); qreal dpi = 100.0; - if (screens.length() > 0) { - const QXcbScreen *screen = screens.at(defaultConnection()->primaryScreen()); + if (const QXcbScreen *screen = defaultConnection()->primaryScreen()) { if (screen->logicalDpi().first > dpi) dpi = screen->logicalDpi().first; if (screen->logicalDpi().second > dpi) diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 0d75a7f032..3058b29f2d 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -367,7 +367,7 @@ void *QXcbNativeInterface::x11Screen() QXcbIntegration *integration = static_cast(QGuiApplicationPrivate::platformIntegration()); QXcbConnection *defaultConnection = integration->defaultConnection(); if (defaultConnection) - return reinterpret_cast(defaultConnection->primaryScreen()); + return reinterpret_cast(defaultConnection->primaryScreenNumber()); return 0; } diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index 9ec4ea80ec..40a50f61ab 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -59,7 +59,7 @@ QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) const xcb_atom_t trayAtom = connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_OPCODE); if (!trayAtom) return 0; - const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreen()); + const QByteArray netSysTray = QByteArrayLiteral("_NET_SYSTEM_TRAY_S") + QByteArray::number(connection->primaryScreenNumber()); const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); if (!selection) return 0; @@ -145,11 +145,8 @@ QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) inline void QXcbSystemTrayTracker::emitSystemTrayWindowChanged() { - const int screen = m_connection->primaryScreen(); - if (screen >= 0 && screen < m_connection->screens().size()) { - const QPlatformScreen *ps = m_connection->screens().at(screen); + if (const QPlatformScreen *ps = m_connection->primaryScreen()) emit systemTrayWindowChanged(ps->screen()); - } } // Client messages with the "MANAGER" atom on the root window indicate creation of a new tray. diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index 0458be32f6..1be9ab3e05 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -56,7 +56,7 @@ void QXcbWMSupport::updateNetWMAtoms() { net_wm_atoms.clear(); - xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + xcb_window_t root = connection()->primaryScreen()->root(); int offset = 0; int remaining = 0; do { @@ -90,7 +90,7 @@ void QXcbWMSupport::updateVirtualRoots() if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS))) return; - xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + xcb_window_t root = connection()->primaryScreen()->root(); int offset = 0; int remaining = 0; do { From 933fab137dcaa8bff2a65ca67918f2765875d2cf Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Mon, 27 Oct 2014 12:20:50 +0100 Subject: [PATCH 062/323] Cocoa: Fix regression in key handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The text should be empty when Cmd key is in modifiers. Task-number: QTBUG-36281 Change-Id: Ic71e532695ad4a947c86e8d21ae864d70f9afa4c Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qnsview.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 1fb30567bc..d109ce1db6 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1393,7 +1393,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QString text; // ignore text for the U+F700-U+F8FF range. This is used by Cocoa when // delivering function keys (e.g. arrow keys, backspace, F1-F35, etc.) - if (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff) + if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) text = QCFString::toQString(characters); QWindow *focusWindow = [self topLevelWindow]; From 3d5fb54eda2330d76c11a10c39fc70541eddf4a5 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 29 Oct 2014 08:44:40 +0100 Subject: [PATCH 063/323] Cocoa: Handle Qt::WA_MacAlwaysShowToolWindow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forward the flag to QWindow by setting the _q_macAlwaysShowToolWindowproperty on the window in QWidgetPrivate::create_sys(). Test for the property when creating the window. Task-number: QTBUG-29816 Done-with: Morten Sørvig Change-Id: Id810dda98d02deb0902192cce1783d8b16b04d04 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoawindow.mm | 6 +++++- src/widgets/kernel/qwidget.cpp | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ad6390788a..f536e20b39 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1400,7 +1400,11 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() if ((type & Qt::Popup) == Qt::Popup) [window setHasShadow:YES]; - [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool]; + // Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set. + QVariant showWithoutActivating = QPlatformWindow::window()->property("_q_macAlwaysShowToolWindow"); + bool shouldHideOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && + !(showWithoutActivating.isValid() && showWithoutActivating.toBool()); + [window setHidesOnDeactivate: shouldHideOnDeactivate]; // Make popup windows show on the same desktop as the parent full-screen window. [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 7533cacbdc..cc262fa3e2 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1405,6 +1405,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO if (q->testAttribute(Qt::WA_ShowWithoutActivating)) win->setProperty("_q_showWithoutActivating", QVariant(true)); + if (q->testAttribute(Qt::WA_MacAlwaysShowToolWindow)) + win->setProperty("_q_macAlwaysShowToolWindow", QVariant::fromValue(QVariant(true))); win->setFlags(data.window_flags); fixPosIncludesFrame(); if (q->testAttribute(Qt::WA_Moved) From 824f01af8ffb39d94807c2b27d1259b9206b3014 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 29 Oct 2014 10:30:17 +0100 Subject: [PATCH 064/323] fontconfig: do not assume the path to a font file is Latin1-encoded Task-number: QTBUG-42249 Change-Id: Ie5d41ed26a69103991a5189c4f42aa37ac73de26 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Liang Qi --- .../fontdatabases/fontconfig/qfontconfigdatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 2b9883eb36..5dec1d0915 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -409,7 +409,7 @@ static void populateFromPattern(FcPattern *pattern) #endif FontFile *fontFile = new FontFile; - fontFile->fileName = QLatin1String((const char *)file_value); + fontFile->fileName = QString::fromLocal8Bit((const char *)file_value); fontFile->indexValue = indexValue; QFont::Style style = (slant_value == FC_SLANT_ITALIC) From c99b93e55c642cd8bf33cfe54efede623d5ca553 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 20 Oct 2014 15:53:54 +0200 Subject: [PATCH 065/323] QTextCodec: Fix source code indentation Change-Id: Ia9a79e659e028eb6173a7adef12d4973f78c32e9 Reviewed-by: Liang Qi --- src/corelib/codecs/qtextcodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 9af307ca17..bceead72f3 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -503,7 +503,7 @@ QTextCodec *QTextCodec::codecForName(const QByteArray &name) QCoreGlobalData *globalData = QCoreGlobalData::instance(); if (!globalData) return 0; - setup(); + setup(); #ifndef QT_USE_ICU QTextCodecCache *cache = &globalData->codecCache; From ec103617c2fa67b0ac3d56aae5ca4b069efbaf48 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 27 Oct 2014 12:40:11 +0100 Subject: [PATCH 066/323] eglfs: Remove unused member variable Change-Id: I45cdf79c14b823b3e93ed0e0923cb687a0ea17c7 Reviewed-by: Louai Al-Khanji --- src/plugins/platforms/eglfs/qeglfsscreen.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 4938d66538..132646d7a6 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -77,7 +77,6 @@ protected: private: friend class QEglFSWindow; - EGLDisplay m_dpy; EGLSurface m_surface; QEGLPlatformCursor *m_cursor; QEGLPlatformWindow *m_rootWindow; From 0b49ce2f8e69046766bd9eb9adb903ab1d73285f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 29 Oct 2014 14:29:38 +0100 Subject: [PATCH 067/323] Android: QtActivitiyDelegate: extras can be null Change-Id: I3b31cc499067540e6ad7b6d05df75d9ba0e1e615 Reviewed-by: BogDan Vatra --- .../qt5/android/QtActivityDelegate.java | 322 +++++++++--------- 1 file changed, 161 insertions(+), 161 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 7642bc38b5..62a0263780 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -492,190 +492,190 @@ public class QtActivityDelegate // FIXME turn on debuggable check // if the applications is debuggable and it has a native debug request Bundle extras = m_activity.getIntent().getExtras(); - if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 - &&*/ extras != null - && extras.containsKey("native_debug") - && extras.getString("native_debug").equals("true")) { - try { - String packagePath = - m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(), - PackageManager.GET_CONFIGURATIONS).dataDir + "/"; - String gdbserverPath = - extras.containsKey("gdbserver_path") - ? extras.getString("gdbserver_path") - : packagePath+"lib/gdbserver "; + if (extras != null) { - String socket = - extras.containsKey("gdbserver_socket") - ? extras.getString("gdbserver_socket") - : "+debug-socket"; + if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 + &&*/ extras.containsKey("native_debug") + && extras.getString("native_debug").equals("true")) { + try { + String packagePath = + m_activity.getPackageManager().getApplicationInfo(m_activity.getPackageName(), + PackageManager.GET_CONFIGURATIONS).dataDir + "/"; + String gdbserverPath = + extras.containsKey("gdbserver_path") + ? extras.getString("gdbserver_path") + : packagePath+"lib/gdbserver "; - if (!(new File(gdbserverPath)).exists()) - gdbserverPath += ".so"; + String socket = + extras.containsKey("gdbserver_socket") + ? extras.getString("gdbserver_socket") + : "+debug-socket"; - // start debugger - m_debuggerProcess = Runtime.getRuntime().exec(gdbserverPath - + socket - + " --attach " - + android.os.Process.myPid(), - null, - new File(packagePath)); - } catch (IOException ioe) { - Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage()); - } catch (SecurityException se) { - Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage()); - } catch (NameNotFoundException e) { - Log.e(QtNative.QtTAG,"Can't start debugger" + e.getMessage()); + if (!(new File(gdbserverPath)).exists()) + gdbserverPath += ".so"; + + // start debugger + m_debuggerProcess = Runtime.getRuntime().exec(gdbserverPath + + socket + + " --attach " + + android.os.Process.myPid(), + null, + new File(packagePath)); + } catch (IOException ioe) { + Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage()); + } catch (SecurityException se) { + Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage()); + } catch (NameNotFoundException e) { + Log.e(QtNative.QtTAG,"Can't start debugger" + e.getMessage()); + } } - } - if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 - &&*/ extras != null - && extras.containsKey("debug_ping") - && extras.getString("debug_ping").equals("true")) { - try { - debugLog("extra parameters: " + extras); - String packageName = m_activity.getPackageName(); - String pingFile = extras.getString("ping_file"); - String pongFile = extras.getString("pong_file"); - String gdbserverSocket = extras.getString("gdbserver_socket"); - String gdbserverCommand = extras.getString("gdbserver_command"); - boolean usePing = pingFile != null; - boolean usePong = pongFile != null; - boolean useSocket = gdbserverSocket != null; - int napTime = 200; // milliseconds between file accesses - int timeOut = 30000; // ms until we give up on ping and pong - int maxAttempts = timeOut / napTime; + if ( /*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 + &&*/ extras.containsKey("debug_ping") + && extras.getString("debug_ping").equals("true")) { + try { + debugLog("extra parameters: " + extras); + String packageName = m_activity.getPackageName(); + String pingFile = extras.getString("ping_file"); + String pongFile = extras.getString("pong_file"); + String gdbserverSocket = extras.getString("gdbserver_socket"); + String gdbserverCommand = extras.getString("gdbserver_command"); + boolean usePing = pingFile != null; + boolean usePong = pongFile != null; + boolean useSocket = gdbserverSocket != null; + int napTime = 200; // milliseconds between file accesses + int timeOut = 30000; // ms until we give up on ping and pong + int maxAttempts = timeOut / napTime; - if (gdbserverSocket != null) { - debugLog("removing gdb socket " + gdbserverSocket); - new File(gdbserverSocket).delete(); - } - - if (usePing) { - debugLog("removing ping file " + pingFile); - File ping = new File(pingFile); - if (ping.exists()) { - if (!ping.delete()) - debugLog("ping file cannot be deleted"); + if (gdbserverSocket != null) { + debugLog("removing gdb socket " + gdbserverSocket); + new File(gdbserverSocket).delete(); } - } - if (usePong) { - debugLog("removing pong file " + pongFile); - File pong = new File(pongFile); - if (pong.exists()) { - if (!pong.delete()) - debugLog("pong file cannot be deleted"); - } - } - - debugLog("starting " + gdbserverCommand); - m_debuggerProcess = Runtime.getRuntime().exec(gdbserverCommand); - debugLog("gdbserver started"); - - if (useSocket) { - int i; - for (i = 0; i < maxAttempts; ++i) { - debugLog("waiting for socket at " + gdbserverSocket + ", attempt " + i); - File file = new File(gdbserverSocket); - if (file.exists()) { - file.setReadable(true, false); - file.setWritable(true, false); - file.setExecutable(true, false); - break; + if (usePing) { + debugLog("removing ping file " + pingFile); + File ping = new File(pingFile); + if (ping.exists()) { + if (!ping.delete()) + debugLog("ping file cannot be deleted"); } - Thread.sleep(napTime); } - if (i == maxAttempts) { - debugLog("time out when waiting for socket"); - return false; - } - - debugLog("socket ok"); - } else { - debugLog("socket not used"); - } - - if (usePing) { - // Tell we are ready. - debugLog("writing ping at " + pingFile); - FileWriter writer = new FileWriter(pingFile); - writer.write("" + android.os.Process.myPid()); - writer.close(); - File file = new File(pingFile); - file.setReadable(true, false); - file.setWritable(true, false); - file.setExecutable(true, false); - debugLog("wrote ping"); - } else { - debugLog("ping not requested"); - } - - // Wait until other side is ready. - if (usePong) { - int i; - for (i = 0; i < maxAttempts; ++i) { - debugLog("waiting for pong at " + pongFile + ", attempt " + i); - File file = new File(pongFile); - if (file.exists()) { - file.delete(); - break; + if (usePong) { + debugLog("removing pong file " + pongFile); + File pong = new File(pongFile); + if (pong.exists()) { + if (!pong.delete()) + debugLog("pong file cannot be deleted"); } - debugLog("go to sleep"); - Thread.sleep(napTime); - } - debugLog("Removing pingFile " + pingFile); - new File(pingFile).delete(); - - if (i == maxAttempts) { - debugLog("time out when waiting for pong file"); - return false; } - debugLog("got pong " + pongFile); - } else { - debugLog("pong not requested"); + debugLog("starting " + gdbserverCommand); + m_debuggerProcess = Runtime.getRuntime().exec(gdbserverCommand); + debugLog("gdbserver started"); + + if (useSocket) { + int i; + for (i = 0; i < maxAttempts; ++i) { + debugLog("waiting for socket at " + gdbserverSocket + ", attempt " + i); + File file = new File(gdbserverSocket); + if (file.exists()) { + file.setReadable(true, false); + file.setWritable(true, false); + file.setExecutable(true, false); + break; + } + Thread.sleep(napTime); + } + + if (i == maxAttempts) { + debugLog("time out when waiting for socket"); + return false; + } + + debugLog("socket ok"); + } else { + debugLog("socket not used"); + } + + if (usePing) { + // Tell we are ready. + debugLog("writing ping at " + pingFile); + FileWriter writer = new FileWriter(pingFile); + writer.write("" + android.os.Process.myPid()); + writer.close(); + File file = new File(pingFile); + file.setReadable(true, false); + file.setWritable(true, false); + file.setExecutable(true, false); + debugLog("wrote ping"); + } else { + debugLog("ping not requested"); + } + + // Wait until other side is ready. + if (usePong) { + int i; + for (i = 0; i < maxAttempts; ++i) { + debugLog("waiting for pong at " + pongFile + ", attempt " + i); + File file = new File(pongFile); + if (file.exists()) { + file.delete(); + break; + } + debugLog("go to sleep"); + Thread.sleep(napTime); + } + debugLog("Removing pingFile " + pingFile); + new File(pingFile).delete(); + + if (i == maxAttempts) { + debugLog("time out when waiting for pong file"); + return false; + } + + debugLog("got pong " + pongFile); + } else { + debugLog("pong not requested"); + } + + } catch (IOException ioe) { + Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage()); + } catch (SecurityException se) { + Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage()); } - - } catch (IOException ioe) { - Log.e(QtNative.QtTAG,"Can't start debugger" + ioe.getMessage()); - } catch (SecurityException se) { - Log.e(QtNative.QtTAG,"Can't start debugger" + se.getMessage()); } - } - if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 - &&*/ extras != null - && extras.containsKey("qml_debug") - && extras.getString("qml_debug").equals("true")) { - String qmljsdebugger; - if (extras.containsKey("qmljsdebugger")) { - qmljsdebugger = extras.getString("qmljsdebugger"); - qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security - } else { - qmljsdebugger = "port:3768"; + if (/*(ai.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0 + &&*/ extras.containsKey("qml_debug") + && extras.getString("qml_debug").equals("true")) { + String qmljsdebugger; + if (extras.containsKey("qmljsdebugger")) { + qmljsdebugger = extras.getString("qmljsdebugger"); + qmljsdebugger.replaceAll("\\s", ""); // remove whitespace for security + } else { + qmljsdebugger = "port:3768"; + } + m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger; } - m_applicationParameters += "\t-qmljsdebugger=" + qmljsdebugger; - } - if (extras.containsKey("extraenvvars")) { - try { - m_environmentVariables += "\t" + new String(Base64.decode(extras.getString("extraenvvars"), Base64.DEFAULT), "UTF-8"); - } catch (Exception e) { - e.printStackTrace(); + if (extras.containsKey("extraenvvars")) { + try { + m_environmentVariables += "\t" + new String(Base64.decode(extras.getString("extraenvvars"), Base64.DEFAULT), "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } } - } - if (extras.containsKey("extraappparams")) { - try { - m_applicationParameters += "\t" + new String(Base64.decode(extras.getString("extraappparams"), Base64.DEFAULT), "UTF-8"); - } catch (Exception e) { - e.printStackTrace(); + if (extras.containsKey("extraappparams")) { + try { + m_applicationParameters += "\t" + new String(Base64.decode(extras.getString("extraappparams"), Base64.DEFAULT), "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } } - } + } // extras != null if (null == m_surfaces) onCreate(null); From 136ccaa276574ba540f7fbed8173f7ae4c5680af Mon Sep 17 00:00:00 2001 From: John Brooks Date: Wed, 15 Oct 2014 15:55:36 -0600 Subject: [PATCH 068/323] Ignore alert on an active window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When QWindow::alert() is called with a duration of 0, it calls QPlatformWindow::setAlertState(true), and expects the alert state to be reset when the window is next activated. Other calls to alert are ignored while alertState is still true. If alert was called for an active window, it would remain in the alert state until deactivated and activated again, and on some platforms calls to alert would be broken while deactivated. Alerting doesn't make sense for active windows, so we can simply ignore it, which was the behavior with Qt 4 on some platforms. Change-Id: Ia3324da4c89db711b63eb31cddf0bf742bb4e3b8 Found-By: Jan Noertemann Reviewed-by: Friedemann Kleint Reviewed-by: Martin Gräßlin Reviewed-by: Shawn Rutledge --- src/gui/kernel/qwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index af3b27fd10..b0fbbc1570 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2299,7 +2299,7 @@ QWindow *QWindow::fromWinId(WId id) /*! Causes an alert to be shown for \a msec miliseconds. If \a msec is \c 0 (the default), then the alert is shown indefinitely until the window becomes - active again. + active again. This function has no effect on an active window. In alert state, the window indicates that it demands attention, for example by flashing or bouncing the taskbar entry. @@ -2310,7 +2310,7 @@ QWindow *QWindow::fromWinId(WId id) void QWindow::alert(int msec) { Q_D(QWindow); - if (!d->platformWindow || d->platformWindow->isAlertState()) + if (!d->platformWindow || d->platformWindow->isAlertState() || isActive()) return; d->platformWindow->setAlertState(true); if (d->platformWindow->isAlertState() && msec) From 6ee73677b25b613b7698b9cdc850415455dbaadb Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Wed, 29 Oct 2014 23:33:50 +0100 Subject: [PATCH 069/323] Correct QStandardPaths::DataLocation return value for iOS Currently DataLocation returns the same value as DocumentsLocation which doesn't fit the purpose for what should go in this directory. This patch aims to correct that. On a side note, it will also be more inline with OS X current behavior [ChangeLog][QtCore][iOS] Fixed path to QStandardPaths::DataLocation. Until now DataLocation was pointing to the Document directory. With this patch, it will return the more accurate Library/Application Support. Application making use of DataLocation should move these data to the new location. This can be done using the path provided by DocumentLocation as source path. Task-number: QTBUG-42276 Change-Id: I35415643cf8cc7a60528f9b0fb5028ada5deace0 Reviewed-by: Jake Petroules Reviewed-by: David Faure --- src/corelib/io/qstandardpaths_ios.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/io/qstandardpaths_ios.mm b/src/corelib/io/qstandardpaths_ios.mm index cdca28b8b5..9b500f4623 100644 --- a/src/corelib/io/qstandardpaths_ios.mm +++ b/src/corelib/io/qstandardpaths_ios.mm @@ -92,6 +92,8 @@ QString QStandardPaths::writableLocation(StandardLocation type) break; case AppDataLocation: case AppLocalDataLocation: + location = pathForDirectory(NSApplicationSupportDirectory); + break; case GenericDataLocation: location = pathForDirectory(NSDocumentDirectory); break; From a860500f8e7f705939ce489849e73c640d4316ce Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 22 Oct 2014 09:18:33 -0400 Subject: [PATCH 070/323] Adapt the names in the documentation to the names used in the header This is needed since the names of the header are the ones you have to use in the QML signal handlers to access the variables Change-Id: I507e2ccc05a1fd2c5efd0bf4bef92ed33a186d95 Reviewed-by: Simon Hausmann --- src/corelib/itemmodels/qabstractitemmodel.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 74a7ea1988..6b89c8377a 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1552,13 +1552,13 @@ QAbstractItemModel::~QAbstractItemModel() */ /*! - \fn void QAbstractItemModel::rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) + \fn void QAbstractItemModel::rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) \since 4.6 This signal is emitted after rows have been moved within the - model. The items between \a sourceStart and \a sourceEnd - inclusive, under the given \a sourceParent item have been moved to \a destinationParent - starting at the row \a destinationRow. + model. The items between \a start and \a end + inclusive, under the given \a parent item have been moved to \a destination + starting at the row \a row. \b{Note:} Components connected to this signal use it to adapt to changes in the model's dimensions. It can only be emitted by the QAbstractItemModel @@ -1584,13 +1584,13 @@ QAbstractItemModel::~QAbstractItemModel() */ /*! - \fn void QAbstractItemModel::columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn) + \fn void QAbstractItemModel::columnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column) \since 4.6 This signal is emitted after columns have been moved within the - model. The items between \a sourceStart and \a sourceEnd - inclusive, under the given \a sourceParent item have been moved to \a destinationParent - starting at the column \a destinationColumn. + model. The items between \a start and \a end + inclusive, under the given \a parent item have been moved to \a destination + starting at the column \a column. \b{Note:} Components connected to this signal use it to adapt to changes in the model's dimensions. It can only be emitted by the QAbstractItemModel From 3f3955fec533c77639d6f1eb20cff593597d6222 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 27 Oct 2014 18:39:26 +0100 Subject: [PATCH 071/323] QMacStyle: Fix QCombobox offsets in Yosemite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-40833 Change-Id: Id3c3f4fd4f5c72cba844bf23f2e79ce0ea2b4a95 Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 1d4aab7686..446946d793 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -4075,7 +4075,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter comboCopy.direction = Qt::LeftToRight; if (opt->state & QStyle::State_Small) comboCopy.rect.translate(0, w ? (QSysInfo::macVersion() > QSysInfo::MV_10_8 ? 0 : -1) : -2); // Supports Qt Quick Controls - else if (QSysInfo::macVersion() > QSysInfo::MV_10_8) + else if (QSysInfo::macVersion() == QSysInfo::MV_10_9) comboCopy.rect.translate(0, 1); QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); } @@ -5738,10 +5738,13 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex if (const QStyleOptionComboBox *combo = qstyleoption_cast(opt)){ HIThemeButtonDrawInfo bdi; d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state)); + HIRect rect = qt_hirectForQRect(combo->rect); + if (combo->editable && QSysInfo::MacintoshVersion > QSysInfo::MV_10_9) + rect.origin.y += tds == kThemeStateInactive ? 1 : 2; if (tds != kThemeStateInactive) - QMacStylePrivate::drawCombobox(qt_hirectForQRect(combo->rect), bdi, p); + QMacStylePrivate::drawCombobox(rect, bdi, p); else - d->drawColorlessButton(qt_hirectForQRect(combo->rect), &bdi, p, opt); + d->drawColorlessButton(rect, &bdi, p, opt); } break; case CC_TitleBar: From c9b49612fff597498a03a5d8161765f03bc54e53 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Tue, 28 Oct 2014 19:17:01 +0100 Subject: [PATCH 072/323] QMacStyle: Several fixes for QtQuick Controls on Yosemite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some offsets differ between QWidgets and Controls. Therefore, we need drawNSViewInRect() to know about the origin of the call. Change-Id: I3bd165f94731f2b37423d86ed5d3c302a17d5ef5 Task-number: QTBUG-42067 Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 25 +++++++++++-------------- src/widgets/styles/qmacstyle_mac_p_p.h | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 446946d793..21ecdbc034 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1897,7 +1897,7 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const return bv; } -void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, QCocoaDrawRectBlock drawRectBlock) const +void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &qtRect, QPainter *p, bool isQWidget, QCocoaDrawRectBlock drawRectBlock) const { QPoint offset; if (widget == QCocoaWidget(QCocoaRadioButton, QAquaSizeLarge)) @@ -1916,16 +1916,15 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const else if (widget == QCocoaWidget(QCocoaPopupButton, QAquaSizeMini)) offset = QPoint(2, -1); else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeLarge)) - offset = QPoint(3, -1); + offset = isQWidget ? QPoint(3, -1) : QPoint(-1, -3); else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeSmall)) offset = QPoint(2, 1); else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeMini)) offset = QPoint(5, 0); - p->translate(offset); - QMacCGContext ctx(p); CGContextSaveGState(ctx); + CGContextTranslateCTM(ctx, offset.x(), offset.y()); [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext @@ -1943,8 +1942,6 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const [NSGraphicsContext restoreGraphicsState]; CGContextRestoreGState(ctx); - - p->translate(-offset); } void QMacStylePrivate::resolveCurrentNSView(QWindow *window) @@ -3883,15 +3880,14 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } if (hasMenu && yosemiteOrLater && bdi.kind != kThemeBevelButton) { - QCocoaWidget w = cocoaWidgetFromHIThemeButtonKind(bdi.kind); - w.first = QCocoaPullDownButton; - QPoint offset; - NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(w); + QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind); + cw.first = QCocoaPullDownButton; + NSPopUpButton *pdb = (NSPopUpButton *)d->cocoaControl(cw); [pdb highlight:(bdi.state == kThemeStatePressed)]; pdb.enabled = bdi.state != kThemeStateUnavailable && bdi.state != kThemeStateUnavailableInactive; QRect rect = opt->rect; - rect.adjust(0, 0, w.second == QAquaSizeSmall ? -4 : w.second == QAquaSizeMini ? -9 : -6, 0); - d->drawNSViewInRect(w, pdb, rect, p); + rect.adjust(0, 0, cw.second == QAquaSizeSmall ? -4 : cw.second == QAquaSizeMini ? -9 : -6, 0); + d->drawNSViewInRect(cw, pdb, rect, p, w != 0); } else if (hasMenu && bdi.state == kThemeStatePressed) d->drawColorlessButton(newRect, &bdi, p, opt); else @@ -4074,7 +4070,8 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter QStyleOptionComboBox comboCopy = *cb; comboCopy.direction = Qt::LeftToRight; if (opt->state & QStyle::State_Small) - comboCopy.rect.translate(0, w ? (QSysInfo::macVersion() > QSysInfo::MV_10_8 ? 0 : -1) : -2); // Supports Qt Quick Controls + comboCopy.rect.translate(0, w ? (QSysInfo::macVersion() > QSysInfo::MV_10_8 ? 0 : -1) : + (QSysInfo::macVersion() > QSysInfo::MV_10_9 ? 0 : -2)); // Supports Qt Quick Controls else if (QSysInfo::macVersion() == QSysInfo::MV_10_9) comboCopy.rect.translate(0, 1); QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p, w); @@ -5563,7 +5560,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex sl.maxValue = slider->maximum; sl.intValue = slider->sliderValue; sl.enabled = slider->state & QStyle::State_Enabled; - d->drawNSViewInRect(cw, sl, opt->rect, p, ^(NSRect rect, CGContextRef ctx) { + d->drawNSViewInRect(cw, sl, opt->rect, p, widget != 0, ^(NSRect rect, CGContextRef ctx) { if (slider->upsideDown) { if (isHorizontal) { CGContextTranslateCTM(ctx, rect.size.width, 0); diff --git a/src/widgets/styles/qmacstyle_mac_p_p.h b/src/widgets/styles/qmacstyle_mac_p_p.h index 80b0afe4a4..89a95713b7 100644 --- a/src/widgets/styles/qmacstyle_mac_p_p.h +++ b/src/widgets/styles/qmacstyle_mac_p_p.h @@ -206,7 +206,7 @@ public: NSView *cocoaControl(QCocoaWidget widget) const; - void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, QCocoaDrawRectBlock drawRectBlock = nil) const; + void drawNSViewInRect(QCocoaWidget widget, NSView *view, const QRect &rect, QPainter *p, bool isQWidget = true, QCocoaDrawRectBlock drawRectBlock = nil) const; void resolveCurrentNSView(QWindow *window); public: From 51ec20d93e97c777fc89e96d8d035d999c8a4ad9 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 20 Oct 2014 16:16:54 +0200 Subject: [PATCH 073/323] Load default codecs even if custom QTextCodec has been registered Task-number: QTBUG-40378 Change-Id: I33f1e92127972e1346993aa4e07731bf4b697667 Reviewed-by: Lars Knoll --- src/corelib/codecs/qtextcodec.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index bceead72f3..d2857c03b6 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -253,9 +253,10 @@ static QTextCodec *setupLocaleMapper() // textCodecsMutex need to be locked to enter this function static void setup() { - QCoreGlobalData *globalData = QCoreGlobalData::instance(); - if (!globalData->allCodecs.isEmpty()) + static bool initialized = false; + if (initialized) return; + initialized = true; #if !defined(QT_NO_CODECS) && !defined(QT_BOOTSTRAPPED) (void)new QTsciiCodec; @@ -465,7 +466,11 @@ QTextCodec::QTextCodec() { QMutexLocker locker(textCodecsMutex()); - QCoreGlobalData::instance()->allCodecs.prepend(this); + QCoreGlobalData *globalInstance = QCoreGlobalData::instance(); + if (globalInstance->allCodecs.isEmpty()) + setup(); + + globalInstance->allCodecs.prepend(this); } From 6c58c9b3ec78ecdd3f72f601041ac34bf2c59320 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 28 Oct 2014 16:06:43 +0100 Subject: [PATCH 074/323] clang: Fix compilation with -openssl-linked Fixes errors like qsslsocket_openssl_symbols.cpp:111:6: error: unused function 'qsslSocketUnresolvedSymbolWarning' [-Werror,-Wunused-function] void qsslSocketUnresolvedSymbolWarning(const char *functionName) ^ 1 error generated. Change-Id: I164518de583f080724ab9a7165c885602a1c6231 Reviewed-by: Richard J. Moore --- src/network/ssl/qsslsocket_openssl_symbols.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index d919d8e934..f4562cdb21 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -107,6 +107,8 @@ QT_BEGIN_NAMESPACE possibly with a different version of OpenSSL. */ +#ifndef QT_LINKED_OPENSSL + namespace { void qsslSocketUnresolvedSymbolWarning(const char *functionName) { @@ -119,6 +121,8 @@ void qsslSocketCannotResolveSymbolWarning(const char *functionName) } } +#endif // QT_LINKED_OPENSSL + #ifdef SSLEAY_MACROS DEFINEFUNC3(void *, ASN1_dup, i2d_of_void *a, a, d2i_of_void *b, b, char *c, c, return 0, return) #endif From 68d4eec30b84009672103574aa4b09ef259a420a Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 28 Oct 2014 16:20:09 +0100 Subject: [PATCH 075/323] Use exising host / port for securesocketclient example Change-Id: I321622b393ea1f452805299d74a28d12270b2238 Reviewed-by: Richard J. Moore --- examples/network/securesocketclient/sslclient.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/network/securesocketclient/sslclient.ui b/examples/network/securesocketclient/sslclient.ui index 4b81fe46eb..19bae83a09 100644 --- a/examples/network/securesocketclient/sslclient.ui +++ b/examples/network/securesocketclient/sslclient.ui @@ -26,7 +26,7 @@ - imap.example.com + www.qt.io @@ -46,7 +46,7 @@ 65535 - 993 + 443 From a5c624622becc8cdf5a1bcd6f8b8e3c1cca53371 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 28 Oct 2014 16:17:19 +0100 Subject: [PATCH 076/323] Fix compiler warning in securesocketclient example The warning was introduced in a133cea2 . Change-Id: Ia8180b6c7d83f57cba79519bf4c0e3bf97966c16 Reviewed-by: Richard J. Moore --- examples/network/securesocketclient/sslclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network/securesocketclient/sslclient.cpp b/examples/network/securesocketclient/sslclient.cpp index 23ca7e41e7..0cec70c742 100644 --- a/examples/network/securesocketclient/sslclient.cpp +++ b/examples/network/securesocketclient/sslclient.cpp @@ -181,7 +181,7 @@ void SslClient::sendData() form->sessionInput->clear(); } -void SslClient::socketError(QAbstractSocket::SocketError error) +void SslClient::socketError(QAbstractSocket::SocketError) { QMessageBox::critical(this, tr("Connection error"), socket->errorString()); } From 848d29cca3afa92f1ae729a1c882e8e3e56fb3e3 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 17 Oct 2014 14:20:02 +0200 Subject: [PATCH 077/323] Raspi: default platform plugin is eglfs Not wayland. Use the default of eglfs coming from linux_device_pre.conf. Qt 5.4 includes QtWayland and the platform plugin from there may get built unexpectedly. The result is that the Pi setup that worked with 5.3 and eglfs stops functioning. Task-number: QTBUG-40538 Change-Id: If894c7ddd7b40a22272797d94ce1a545b7ab43f2 Reviewed-by: Louai Al-Khanji Reviewed-by: Andy Nichols --- mkspecs/devices/linux-rasp-pi-g++/qmake.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/mkspecs/devices/linux-rasp-pi-g++/qmake.conf b/mkspecs/devices/linux-rasp-pi-g++/qmake.conf index 5f923ad5c6..6537d457ab 100644 --- a/mkspecs/devices/linux-rasp-pi-g++/qmake.conf +++ b/mkspecs/devices/linux-rasp-pi-g++/qmake.conf @@ -4,8 +4,6 @@ include(../common/linux_device_pre.conf) -QT_QPA_DEFAULT_PLATFORM = wayland - QMAKE_LFLAGS += -Wl,-rpath-link,$$[QT_SYSROOT]/opt/vc/lib QMAKE_LIBDIR_OPENGL_ES2 = $$[QT_SYSROOT]/opt/vc/lib @@ -21,7 +19,6 @@ QMAKE_LIBS_EGL = -lEGL -lGLESv2 contains(DISTRO, squeeze) { #Debian Squeeze: Legacy everything QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 -lEGL - QT_QPA_DEFAULT_PLATFORM = eglfs } else:contains(DISTRO, arch) { #On principle: no wizardry required } else { From 1487a93e46bafb4ee7beb63e59b90265f0ae1fd3 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 12 Jun 2014 09:06:35 +0200 Subject: [PATCH 078/323] Fix a possible use after free Found by coverity. The cachedIcon can be deleted when being inserted into the icon cache (in QCache::insert). So copy it to icon before trying to insert it into the cache. Change-Id: I5ed13c0c7ecb8f8f13285ca5d06237493dbea479 Reviewed-by: Laszlo Agocs --- src/gui/image/qicon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index adbd21a8a0..6f6bf158c8 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -1173,8 +1173,8 @@ QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) QIconEngine * const engine = platformTheme ? platformTheme->createIconEngine(name) : new QIconLoaderEngine(name); QIcon *cachedIcon = new QIcon(engine); - qtIconCache()->insert(name, cachedIcon); icon = *cachedIcon; + qtIconCache()->insert(name, cachedIcon); } // Note the qapp check is to allow lazy loading of static icons From af5f6e35b6f17e06a85aee445d97e61b6b4bba3e Mon Sep 17 00:00:00 2001 From: Fawzi Mohamed Date: Wed, 22 Oct 2014 17:37:02 +0200 Subject: [PATCH 079/323] xcodegenerator: use a copy resource phase if possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commmit 0127962e4772d6c758b954b2fe1d4b676d366b4c the PBXResourcesBuildPhase is used only for ICONS, because the old behavior of using it when target path is not given differed from the documentation and behavior of the makefile generator by using Contents/Resources as target directory when targeting osx. The PBXResouceBuildPhase optimizes png, compiles xib or asset catalogs and copies the rest. The advantage is that it makes it easy to add resources to the bundle, the only problem is that the target directory is always the resource directory. The copy operation currently used does not compile resources, which makes adding .xib (for the Launch File required to support iphone 6) and asset catalogs difficult. So we restore the old 5.3 behavior for ios, and use the build resources phase when possible on osx (target Contents/Resources). On osx this still implies a difference between the makefile generator and the xcode generator: only the latter compiles resources. Change-Id: Id1853693e88fc46562b044efdea2bf5f9da2c98c Reviewed-by: Oswald Buddenhagen Reviewed-by: Tor Arne Vestbø --- qmake/generators/mac/pbuilder_pbx.cpp | 40 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 3659621391..4624496e99 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1107,9 +1107,12 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << writeSettings("shellScript", fixForOutput("cp -r $BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME " + escapeFilePath(destDir))) << ";\n" << "\t\t};\n"; } + bool copyBundleResources = project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app"; + ProStringList bundle_resources_files; // Copy Bundle Data if (!project->isEmpty("QMAKE_BUNDLE_DATA")) { ProStringList bundle_file_refs; + bool ios = project->isActiveConfig("ios"); //all bundle data const ProStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA"); @@ -1137,21 +1140,27 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t};\n"; } - QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]); - if (!project->isEmpty(ProKey(bundle_data[i] + ".version"))) { - //### - } + if (copyBundleResources && ((ios && path.isEmpty()) + || (!ios && path == QLatin1String("Contents/Resources")))) { + foreach (const ProString &s, bundle_files) + bundle_resources_files << s; + } else { + QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]); + if (!project->isEmpty(ProKey(bundle_data[i] + ".version"))) { + //### + } - project->values("QMAKE_PBX_BUILDPHASES").append(phase_key); - t << "\t\t" << phase_key << " = {\n" - << "\t\t\t" << writeSettings("name", "Copy '" + bundle_data[i] + "' Files to Bundle") << ";\n" - << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n" - << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";\n" - << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";\n" - << "\t\t\t" << writeSettings("files", bundle_files, SettingsAsList, 4) << ";\n" - << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";\n" - << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n" - << "\t\t};\n"; + project->values("QMAKE_PBX_BUILDPHASES").append(phase_key); + t << "\t\t" << phase_key << " = {\n" + << "\t\t\t" << writeSettings("name", "Copy '" + bundle_data[i] + "' Files to Bundle") << ";\n" + << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n" + << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";\n" + << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";\n" + << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";\n" + << "\t\t\t" << writeSettings("files", bundle_files, SettingsAsList, 4) << ";\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n" + << "\t\t};\n"; + } } QString bundle_data_key = keyFor("QMAKE_PBX_BUNDLE_DATA"); @@ -1166,8 +1175,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) // Copy bundle resources. Optimizes resources, and puts them into the Resources // subdirectory on OSX, but doesn't support paths. - if (project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app") { - ProStringList bundle_resources_files; + if (copyBundleResources) { if (!project->isEmpty("ICON")) { ProString icon = project->first("ICON"); if (icon.length() >= 2 && (icon.at(0) == '"' || icon.at(0) == '\'') && icon.endsWith(icon.at(0))) From dd6876f3fdeb4b95a24fba4ad48cbf445b8fb9f4 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Wed, 29 Oct 2014 14:10:05 -0700 Subject: [PATCH 080/323] QCocoaPrintDevice: fix bad CFRelease CFRelease should be called IFF PMPrinterCopyDescriptionURL succeeds Change-Id: Id289aea3a4e3da397dae4062319256a043538597 Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/qcocoaprintdevice.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index b3551e2c29..c26a2b22fd 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -468,11 +468,11 @@ bool QCocoaPrintDevice::openPpdFile() CFURLRef ppdURL = NULL; char ppdPath[MAXPATHLEN]; if (PMPrinterCopyDescriptionURL(m_printer, kPMPPDDescriptionType, &ppdURL) == noErr - && ppdURL != NULL - && CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath))) { - m_ppd = ppdOpenFile(ppdPath); + && ppdURL != NULL) { + if (CFURLGetFileSystemRepresentation(ppdURL, true, (UInt8*)ppdPath, sizeof(ppdPath))) + m_ppd = ppdOpenFile(ppdPath); + CFRelease(ppdURL); } - CFRelease(ppdURL); return m_ppd ? true : false; } From f3fb787a32aee43441c5802a406f8dbd1eb0a1d6 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Wed, 29 Oct 2014 16:45:33 -0700 Subject: [PATCH 081/323] OS X: fix CFString leaks in mime classes Some CFStringRefs created with CFStringCreate* methods were not being released. Using the QCFString helper class to perform auto release. Change-Id: I36d15c0d35118524089e99ea3cd53c41342d6308 Reviewed-by: Jake Petroules --- src/platformsupport/clipboard/qmacmime.mm | 9 +++++---- src/plugins/platforms/cocoa/qcocoamimetypes.mm | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/platformsupport/clipboard/qmacmime.mm b/src/platformsupport/clipboard/qmacmime.mm index 27a490335b..6fcd19e07b 100644 --- a/src/platformsupport/clipboard/qmacmime.mm +++ b/src/platformsupport/clipboard/qmacmime.mm @@ -48,6 +48,7 @@ #include "qmacmime_p.h" #include "qguiapplication.h" +#include "private/qcore_mac_p.h" QT_BEGIN_NAMESPACE @@ -335,9 +336,9 @@ QVariant QMacPasteboardMimePlainTextFallback::convertToMime(const QString &mimet // Note that public.text is documented by Apple to have an undefined encoding. From // testing it seems that utf8 is normally used, at least by Safari on iOS. const QByteArray &firstData = data.first(); - return QString::fromCFString(CFStringCreateWithBytes(kCFAllocatorDefault, + return QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast(firstData.constData()), - firstData.size(), kCFStringEncodingUTF8, false)); + firstData.size(), kCFStringEncodingUTF8, false))); } else { qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); } @@ -410,9 +411,9 @@ QVariant QMacPasteboardMimeUnicodeText::convertToMime(const QString &mimetype, Q // I can only handle two types (system and unicode) so deal with them that way QVariant ret; if (flavor == QLatin1String("public.utf8-plain-text")) { - ret = QString::fromCFString(CFStringCreateWithBytes(kCFAllocatorDefault, + ret = QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast(firstData.constData()), - firstData.size(), CFStringGetSystemEncoding(), false)); + firstData.size(), CFStringGetSystemEncoding(), false))); } else if (flavor == QLatin1String("public.utf16-plain-text")) { ret = QString(reinterpret_cast(firstData.constData()), firstData.size() / sizeof(QChar)); diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.mm b/src/plugins/platforms/cocoa/qcocoamimetypes.mm index 421d934fa7..b657ef9a82 100644 --- a/src/plugins/platforms/cocoa/qcocoamimetypes.mm +++ b/src/plugins/platforms/cocoa/qcocoamimetypes.mm @@ -88,9 +88,9 @@ QVariant QMacPasteboardMimeTraditionalMacPlainText::convertToMime(const QString const QByteArray &firstData = data.first(); QVariant ret; if (flavor == QLatin1String("com.apple.traditional-mac-plain-text")) { - return QString::fromCFString(CFStringCreateWithBytes(kCFAllocatorDefault, + return QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault, reinterpret_cast(firstData.constData()), - firstData.size(), CFStringGetSystemEncoding(), false)); + firstData.size(), CFStringGetSystemEncoding(), false))); } else { qWarning("QMime::convertToMime: unhandled mimetype: %s", qPrintable(mimetype)); } From 4387c5d6af49976318f7ca04c7a47b81a9cb19cc Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 30 Oct 2014 12:39:10 +0100 Subject: [PATCH 082/323] QWindowsStyle: fix CE_ComboBoxLabel text color CE_ComboBoxLabel was relying on a font color / painter pen set by CC_ComboBox. This change ensures that CE_ComboBoxLabel has correct color when CC_ComboBox and CE_ComboBoxLabel are drawn independently. Change-Id: Id548d831fdde5885bc7c157d55de6235ef3f0a56 Task-number: QTBUG-41702 Reviewed-by: Friedemann Kleint --- src/widgets/styles/qwindowsstyle.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 708014a6df..a10bdc67e1 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -1821,6 +1821,20 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai } return; #endif // QT_NO_DOCKWIDGET +#ifndef QT_NO_COMBOBOX + case CE_ComboBoxLabel: + if (const QStyleOptionComboBox *cb = qstyleoption_cast(opt)) { + if (cb->state & State_HasFocus) { + p->setPen(cb->palette.highlightedText().color()); + p->setBackground(cb->palette.highlight()); + } else { + p->setPen(cb->palette.text().color()); + p->setBackground(cb->palette.background()); + } + } + QCommonStyle::drawControl(ce, opt, p, widget); + break; +#endif // QT_NO_COMBOBOX default: QCommonStyle::drawControl(ce, opt, p, widget); } From 0630c82bd0fa2a4a4275437d58544ffdc8fbdb33 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 30 Oct 2014 16:35:17 +0100 Subject: [PATCH 083/323] Add manual test for touch events. Unlike qtouchevents, this provides a touch area which logs its events and devices. Task-number: QTBUG-40461 Change-Id: Iaaa3589dd692caf8c7078f5ed2ff1e8b2322a369 Reviewed-by: Shawn Rutledge --- tests/manual/manual.pro | 1 + tests/manual/touch/main.cpp | 209 +++++++++++++++++++++++++++++++++++ tests/manual/touch/touch.pro | 5 + 3 files changed, 215 insertions(+) create mode 100644 tests/manual/touch/main.cpp create mode 100644 tests/manual/touch/touch.pro diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index e593756a7d..fe3e624bfe 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -29,6 +29,7 @@ qtabletevent \ qtexteditlist \ qtbug-8933 \ qtouchevent \ +touch \ qwidget_zorder \ repaint \ socketengine \ diff --git a/tests/manual/touch/main.cpp b/tests/manual/touch/main.cpp new file mode 100644 index 0000000000..6b06db614c --- /dev/null +++ b/tests/manual/touch/main.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QDebug operator<<(QDebug debug, const QTouchDevice *d) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QTouchDevice(" << d->name() << ','; + switch (d->type()) { + case QTouchDevice::TouchScreen: + debug << "TouchScreen"; + break; + case QTouchDevice::TouchPad: + debug << "TouchPad"; + break; + } + debug << ", capabilities=" << d->capabilities() + << ", maximumTouchPoints=" << d->maximumTouchPoints() << ')'; + return debug; +} + +typedef QVector EventTypeVector; + +class EventFilter : public QObject { + Q_OBJECT +public: + explicit EventFilter(const EventTypeVector &types, QObject *p) : QObject(p), m_types(types) {} + + bool eventFilter(QObject *, QEvent *) Q_DECL_OVERRIDE; + +signals: + void eventReceived(const QString &); + +private: + const EventTypeVector m_types; +}; + +bool EventFilter::eventFilter(QObject *o, QEvent *e) +{ + static int n = 0; + if (m_types.contains(e->type())) { + QString message; + QDebug(&message) << '#' << n++ << ' ' << o->objectName() << ' ' << e; + emit eventReceived(message); + } + return false; +} + +class TouchTestWidget : public QWidget { +public: + explicit TouchTestWidget(QWidget *parent = 0) : QWidget(parent) + { + setAttribute(Qt::WA_AcceptTouchEvents); + } + + bool event(QEvent *event) Q_DECL_OVERRIDE + { + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + event->accept(); + return true; + default: + break; + } + return QWidget::event(event); + } +}; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(); + QWidget *touchWidget() const { return m_touchWidget; } + +public slots: + void appendToLog(const QString &text) { m_logTextEdit->appendPlainText(text); } + void dumpTouchDevices(); + +private: + QWidget *m_touchWidget; + QPlainTextEdit *m_logTextEdit; +}; + +MainWindow::MainWindow() + : m_touchWidget(new TouchTestWidget) + , m_logTextEdit(new QPlainTextEdit) +{ + setWindowTitle(QStringLiteral("Touch Event Tester ") + QT_VERSION_STR); + + setObjectName("MainWin"); + QMenu *fileMenu = menuBar()->addMenu("File"); + QAction *da = fileMenu->addAction(QStringLiteral("Dump devices")); + da->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); + connect(da, SIGNAL(triggered()), this, SLOT(dumpTouchDevices())); + QAction *qa = fileMenu->addAction(QStringLiteral("Quit")); + qa->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + connect(qa, SIGNAL(triggered()), this, SLOT(close())); + + QSplitter *mainSplitter = new QSplitter(Qt::Vertical); + + m_touchWidget->setObjectName(QStringLiteral("TouchWidget")); + const QSize screenSize = QGuiApplication::primaryScreen()->availableGeometry().size(); + m_touchWidget->setMinimumSize(screenSize / 2); + mainSplitter->addWidget(m_touchWidget); + + m_logTextEdit->setObjectName(QStringLiteral("LogTextEdit")); + m_logTextEdit->setMinimumHeight(screenSize.height() / 4); + mainSplitter->addWidget(m_logTextEdit); + setCentralWidget(mainSplitter); + + dumpTouchDevices(); +} + +void MainWindow::dumpTouchDevices() +{ + QString message; + QDebug debug(&message); + const QList devices = QTouchDevice::devices(); + debug << devices.size() << "Device(s):\n"; + for (int i = 0; i < devices.size(); ++i) + debug << "Device #" << i << devices.at(i) << '\n'; + appendToLog(message); +} + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + QCommandLineParser parser; + parser.setApplicationDescription(QStringLiteral("Touch/Mouse tester")); + parser.addHelpOption(); + const QCommandLineOption mouseMoveOption(QStringLiteral("mousemove"), + QStringLiteral("Log mouse move events")); + parser.addOption(mouseMoveOption); + const QCommandLineOption globalFilterOption(QStringLiteral("global"), + QStringLiteral("Global event filter")); + parser.addOption(globalFilterOption); + parser.process(QApplication::arguments()); + + MainWindow w; + w.show(); + const QSize pos = QGuiApplication::primaryScreen()->availableGeometry().size() - w.size(); + w.move(pos.width() / 2, pos.height() / 2); + + EventTypeVector eventTypes; + eventTypes << QEvent::MouseButtonPress << QEvent::MouseButtonRelease + << QEvent::MouseButtonDblClick + << QEvent::TouchBegin << QEvent::TouchUpdate << QEvent::TouchEnd; + if (parser.isSet(mouseMoveOption)) + eventTypes << QEvent::MouseMove; + QObject *filterTarget = parser.isSet(globalFilterOption) + ? static_cast(&a) + : static_cast(w.touchWidget()); + EventFilter *filter = new EventFilter(eventTypes, filterTarget); + filterTarget->installEventFilter(filter); + QObject::connect(filter, SIGNAL(eventReceived(QString)), &w, SLOT(appendToLog(QString))); + + return a.exec(); +} + +#include "main.moc" diff --git a/tests/manual/touch/touch.pro b/tests/manual/touch/touch.pro new file mode 100644 index 0000000000..fcb3c47f43 --- /dev/null +++ b/tests/manual/touch/touch.pro @@ -0,0 +1,5 @@ +TEMPLATE = app +QT = core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +CONFIG -= app_bundle +SOURCES += main.cpp From 9150e04b17ff34e8525d7836e970798fa8eca414 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 2 Oct 2014 21:58:06 -0700 Subject: [PATCH 084/323] Import the FreeBSD strtoXX functions Obtained from: http://freebsd.googlecode.com/git-history/4658f9721d395818ba760a79b1cb0b54957d4576/lib/libc/stdlib/strtoull.c http://freebsd.googlecode.com/git-history/4658f9721d395818ba760a79b1cb0b54957d4576/lib/libc/stdlib/strtoll.c Changes: - remove the #includes and the SCCSID - rename from strtoxx_l to qt_strtoxx (merging the two functions) - remove __restrict - remove the locale_t parameter and use ascii_isspace instead of isspace_l Change-Id: I1e522e12da90eb35eefcf4025102dc11b22c60a5 Reviewed-by: Oswald Buddenhagen Reviewed-by: Lars Knoll --- ...D-strto-u-ll-functions-to-work-insid.patch | 149 ++++++++++++++++++ src/3rdparty/freebsd/strtoll.c | 134 ++++++++++++++++ src/3rdparty/freebsd/strtoull.c | 112 +++++++++++++ 3 files changed, 395 insertions(+) create mode 100644 src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch create mode 100644 src/3rdparty/freebsd/strtoll.c create mode 100644 src/3rdparty/freebsd/strtoull.c diff --git a/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch b/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch new file mode 100644 index 0000000000..ac7580d5c4 --- /dev/null +++ b/src/3rdparty/freebsd/0001-Patch-the-FreeBSD-strto-u-ll-functions-to-work-insid.patch @@ -0,0 +1,149 @@ +From 81a2d1a38becdeed2cd8b963e190aedf197e39c6 Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Thu, 2 Oct 2014 22:03:19 -0700 +Subject: [PATCH 1/1] Patch the FreeBSD strto(u)ll functions to work inside + QtCore + +Changes: + - remove the #includes and the SCCSID + - rename from strtoxx_l to qt_strtoxx (merging the two functions) + - remove __restrict + - remove the locale_t parameter and use ascii_isspace instead of isspace_l + +Change-Id: I1e522e12da90eb35eefcf4025102dc11b22c60a5 +--- + src/3rdparty/freebsd/strtoll.c | 27 +++++---------------------- + src/3rdparty/freebsd/strtoull.c | 27 +++++---------------------- + 2 files changed, 10 insertions(+), 44 deletions(-) + +diff --git a/src/3rdparty/freebsd/strtoll.c b/src/3rdparty/freebsd/strtoll.c +index 16a8196..0ded267 100644 +--- a/src/3rdparty/freebsd/strtoll.c ++++ b/src/3rdparty/freebsd/strtoll.c +@@ -32,18 +32,6 @@ + * SUCH DAMAGE. + */ + +-#if defined(LIBC_SCCS) && !defined(lint) +-static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93"; +-#endif /* LIBC_SCCS and not lint */ +-#include +-__FBSDID("$FreeBSD$"); +- +-#include +-#include +-#include +-#include +-#include "xlocale_private.h" +- + /* + * Convert a string to a long long integer. + * +@@ -51,15 +39,15 @@ __FBSDID("$FreeBSD$"); + * alphabets and digits are each contiguous. + */ + long long +-strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base, +- locale_t locale) ++qt_strtoll(const char * nptr, char **endptr, int base) + { + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; +- FIX_LOCALE(locale); + + /* + * Skip white space and pick up leading +/- sign if any. +@@ -69,7 +55,7 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base, + s = nptr; + do { + c = *s++; +- } while (isspace_l((unsigned char)c, locale)); ++ } while (ascii_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; +@@ -141,13 +127,8 @@ strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base, + noconv: + errno = EINVAL; + } else if (neg) +- acc = -acc; ++ acc = (unsigned long long) -(long long)acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); + } +-long long +-strtoll(const char * __restrict nptr, char ** __restrict endptr, int base) +-{ +- return strtoll_l(nptr, endptr, base, __get_locale()); +-} +diff --git a/src/3rdparty/freebsd/strtoull.c b/src/3rdparty/freebsd/strtoull.c +index dc40e0e..cb04adb 100644 +--- a/src/3rdparty/freebsd/strtoull.c ++++ b/src/3rdparty/freebsd/strtoull.c +@@ -32,18 +32,6 @@ + * SUCH DAMAGE. + */ + +-#if defined(LIBC_SCCS) && !defined(lint) +-static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93"; +-#endif /* LIBC_SCCS and not lint */ +-#include +-__FBSDID("$FreeBSD$"); +- +-#include +-#include +-#include +-#include +-#include "xlocale_private.h" +- + /* + * Convert a string to an unsigned long long integer. + * +@@ -51,15 +39,15 @@ __FBSDID("$FreeBSD$"); + * alphabets and digits are each contiguous. + */ + unsigned long long +-strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base, +- locale_t locale) ++qt_strtoull(const char * nptr, char **endptr, int base) + { + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; +- FIX_LOCALE(locale); + + /* + * See strtoq for comments as to the logic used. +@@ -67,7 +53,7 @@ strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base, + s = nptr; + do { + c = *s++; +- } while (isspace_l((unsigned char)c, locale)); ++ } while (ascii_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; +@@ -119,13 +105,8 @@ strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base, + noconv: + errno = EINVAL; + } else if (neg) +- acc = -acc; ++ acc = (unsigned long long) -(long long)acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); + } +-unsigned long long +-strtoull(const char * __restrict nptr, char ** __restrict endptr, int base) +-{ +- return strtoull_l(nptr, endptr, base, __get_locale()); +-} +-- +1.8.4.5 + diff --git a/src/3rdparty/freebsd/strtoll.c b/src/3rdparty/freebsd/strtoll.c new file mode 100644 index 0000000000..6f06e03dc8 --- /dev/null +++ b/src/3rdparty/freebsd/strtoll.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Convert a string to a long long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long long +qt_strtoll(const char * nptr, char **endptr, int base) +{ + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (ascii_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for quads is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX + : LLONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LLONG_MIN : LLONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = (unsigned long long) -(long long)acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/src/3rdparty/freebsd/strtoull.c b/src/3rdparty/freebsd/strtoull.c new file mode 100644 index 0000000000..7cb97f02f4 --- /dev/null +++ b/src/3rdparty/freebsd/strtoull.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Convert a string to an unsigned long long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long long +qt_strtoull(const char * nptr, char **endptr, int base) +{ + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; + + /* + * See strtoq for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (ascii_isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULLONG_MAX / base; + cutlim = ULLONG_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULLONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = (unsigned long long) -(long long)acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} From f91b81ca398c64a22fd6fb2006dbec39a3e3b2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 30 Oct 2014 12:37:05 +0100 Subject: [PATCH 085/323] Remove executable mode on qwidget_window.pro Change-Id: Ibb522af33e8490719010af441cce712bdc7a71bf Reviewed-by: Paul Olav Tvete --- tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro diff --git a/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro old mode 100755 new mode 100644 From 85da1625e47cadf0b41e24863e8988e771e50943 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 19 Sep 2014 14:17:46 -0700 Subject: [PATCH 086/323] Attempt to make QFile I/O 64-bit safe Use qint64 wherever possible. The linear buffer is never requested to allocate that much memory (always limited), but at least we ensure we're not dropping bits where we shouldn't. Windows's POSIX compatibility layer is never largefile enabled, so it is always necessary to chunk large reads and writes. On Unix, this will be rare, unless someone passed -no-largefile to configure, for some weird reason. Unfortunately, this is not testable, unless we can allocate a buffer with 4 GB or more in size. The test for this would be to open a file we know to be small, then try to read 4 GB + 1 byte. If everything works correctly, we'll read the full file; if there was a truncation, we'd read one byte. Change-Id: If3ee511bf1de17e0123c85bbcaa463b9972746ce Reviewed-by: Kai Koehne Reviewed-by: Thiago Macieira --- src/corelib/io/qfsfileengine.cpp | 41 ++++++++++++++++++++++---------- src/corelib/io/qiodevice.cpp | 2 +- src/corelib/io/qiodevice_p.h | 18 +++++++------- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 42250b629d..a126690240 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -73,6 +73,17 @@ QT_BEGIN_NAMESPACE # endif #endif +#ifdef Q_OS_WIN +// on Windows, read() and write() use int and unsigned int +typedef int SignedIOType; +typedef unsigned int UnsignedIOType; +#else +typedef ssize_t SignedIOType; +typedef size_t UnsignedIOType; +Q_STATIC_ASSERT_X(sizeof(SignedIOType) == sizeof(UnsignedIOType), + "Unsupported: read/write return a type with different size as the len parameter"); +#endif + /*! \class QFSFileEngine \inmodule QtCore \brief The QFSFileEngine class implements Qt's default file engine. @@ -605,13 +616,16 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len) } else if (fd != -1) { // Unbuffered stdio mode. -#ifdef Q_OS_WIN - int result; -#else - ssize_t result; -#endif + SignedIOType result; do { - result = QT_READ(fd, data + readBytes, size_t(len - readBytes)); + // calculate the chunk size + // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks + // we limit to the size of the signed type, otherwise we could get a negative number as a result + quint64 wantedBytes = quint64(len) - quint64(readBytes); + UnsignedIOType chunkSize = std::numeric_limits::max(); + if (chunkSize > wantedBytes) + chunkSize = wantedBytes; + result = QT_READ(fd, data + readBytes, chunkSize); } while (result > 0 && (readBytes += result) < len); eof = !(result == -1); @@ -722,13 +736,16 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) } else if (fd != -1) { // Unbuffered stdio mode. -#ifdef Q_OS_WIN - int result; -#else - ssize_t result; -#endif + SignedIOType result; do { - result = QT_WRITE(fd, data + writtenBytes, size_t(len - writtenBytes)); + // calculate the chunk size + // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks + // we limit to the size of the signed type, otherwise we could get a negative number as a result + quint64 wantedBytes = quint64(len) - quint64(writtenBytes); + UnsignedIOType chunkSize = std::numeric_limits::max(); + if (chunkSize > wantedBytes) + chunkSize = wantedBytes; + result = QT_WRITE(fd, data + writtenBytes, chunkSize); } while (result > 0 && (writtenBytes += result) < len); } diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 89209e6118..0709a93bad 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -786,7 +786,7 @@ qint64 QIODevice::read(char *data, qint64 maxSize) bool moreToRead = true; do { // Try reading from the buffer. - int lastReadChunkSize = d->buffer.read(data, maxSize); + qint64 lastReadChunkSize = d->buffer.read(data, maxSize); if (lastReadChunkSize > 0) { *d->pPos += lastReadChunkSize; readSoFar += lastReadChunkSize; diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h index 10d92a896d..d764cb0fbb 100644 --- a/src/corelib/io/qiodevice_p.h +++ b/src/corelib/io/qiodevice_p.h @@ -98,19 +98,19 @@ public: first++; return ch; } - int read(char* target, qint64 size) { - int r = qMin(size, len); + qint64 read(char* target, qint64 size) { + qint64 r = qMin(size, len); memcpy(target, first, r); len -= r; first += r; return r; } - int peek(char* target, qint64 size) { - int r = qMin(size, len); + qint64 peek(char* target, qint64 size) { + qint64 r = qMin(size, len); memcpy(target, first, r); return r; } - char* reserve(int size) { + char* reserve(qint64 size) { makeSpace(size + len, freeSpaceAtEnd); char* writePtr = first + len; len += size; @@ -128,16 +128,16 @@ public: clear(); return retVal; } - int readLine(char* target, qint64 size) { - int r = qMin(size, len); + qint64 readLine(char* target, qint64 size) { + qint64 r = qMin(size, len); char* eol = static_cast(memchr(first, '\n', r)); if (eol) r = 1+(eol-first); memcpy(target, first, r); len -= r; first += r; - return int(r); - } + return r; + } bool canReadLine() const { return memchr(first, '\n', len); } From fc2fcacfcc5e644a3463f34e007e89c5f8bfdf22 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 2 Oct 2014 11:49:55 -0700 Subject: [PATCH 087/323] Don't always chmod the XDG_RUNTIME_DIR Since the current user is the owner of the dir, we'll get 0x7700 as permissions, not just 0x700. With the wrong check, we were always doing an unnecessary chmod. Task-number: QTBUG-41735 Change-Id: Ib1fc258fef4bf526baa9c71201f9b78d36f5454f Reviewed-by: David Faure --- src/corelib/io/qstandardpaths_unix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp index 469c223b00..2d08c1c4e6 100644 --- a/src/corelib/io/qstandardpaths_unix.cpp +++ b/src/corelib/io/qstandardpaths_unix.cpp @@ -131,8 +131,10 @@ QString QStandardPaths::writableLocation(StandardLocation type) return QString(); } // "and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700." + // since the current user is the owner, set both xxxUser and xxxOwner QFile file(xdgRuntimeDir); - const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser; + const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser + | QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner; if (file.permissions() != wantedPerms && !file.setPermissions(wantedPerms)) { qWarning("QStandardPaths: wrong permissions on runtime directory %s", qPrintable(xdgRuntimeDir)); return QString(); From d0ed6dc1464bd4b62b765060901de708eec5687d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 2 Oct 2014 11:56:22 -0700 Subject: [PATCH 088/323] Report the system error on why chmod(2) failed in XDG_RUNTIME_DIR This is a very rare occurrence: if the user is the owner of the directory, the user can chmod(2), and we already checked that the user is the owner. However, chmod(2) can still fail on read-only fs and on hardened systems. Task-number: QTBUG-41735 Change-Id: I8f8bac763bf5a6e575ed59dac55bd265e5b66271 Reviewed-by: Oswald Buddenhagen Reviewed-by: David Faure --- src/corelib/io/qstandardpaths_unix.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp index 2d08c1c4e6..2ad6dfa121 100644 --- a/src/corelib/io/qstandardpaths_unix.cpp +++ b/src/corelib/io/qstandardpaths_unix.cpp @@ -136,7 +136,8 @@ QString QStandardPaths::writableLocation(StandardLocation type) const QFile::Permissions wantedPerms = QFile::ReadUser | QFile::WriteUser | QFile::ExeUser | QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner; if (file.permissions() != wantedPerms && !file.setPermissions(wantedPerms)) { - qWarning("QStandardPaths: wrong permissions on runtime directory %s", qPrintable(xdgRuntimeDir)); + qWarning("QStandardPaths: could not set correct permissions on runtime directory %s: %s", + qPrintable(xdgRuntimeDir), qPrintable(file.errorString())); return QString(); } return xdgRuntimeDir; From 5368e44a86a4e0d4582ff5268986ea8bd0fa64ca Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 28 Oct 2014 19:05:43 -0700 Subject: [PATCH 089/323] Autotest: synchronize with the peer before emitting more signals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Several of the unit tests request that the peer emit more than one signal, but only handle one. The rest of the signals stay queued in the socket and will be delivered at the next test, causing it to fail often. This doesn't happen in the tests with the bus. There, we don't receive the extraneous signals due to AddMatch/ReceiveMatch on each signal individually and the synchronous nature of the emission (the signals have already been emitted by the next AddMatch and cannot match it). Task-number: QTBUG-42145 Change-Id: I743a0553074972042fca46b76db5d9e7b3209620 Reviewed-by: Jędrzej Nowacki --- .../qmyserver/qmyserver.cpp | 11 +++++++- .../tst_qdbusabstractadaptor.cpp | 28 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp b/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp index 5263d431d0..b4c16c6fa3 100644 --- a/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp +++ b/tests/auto/dbus/qdbusabstractadaptor/qmyserver/qmyserver.cpp @@ -75,6 +75,11 @@ public slots: return m_conn.isConnected(); } + Q_NOREPLY void requestSync(const QString &seq) + { + emit syncReceived(seq); + } + void emitSignal(const QString& interface, const QString& name, const QDBusVariant& parameter) { if (interface.endsWith('2')) @@ -126,10 +131,14 @@ public slots: valueSpy.clear(); } +signals: + Q_SCRIPTABLE void syncReceived(const QString &sequence); + private slots: - void handleConnection(const QDBusConnection& con) + void handleConnection(QDBusConnection con) { m_conn = con; + con.registerObject(objectPath, this, QDBusConnection::ExportScriptableSignals); } private: diff --git a/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp index 6d25bf2213..9fe6bc790e 100644 --- a/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp +++ b/tests/auto/dbus/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp @@ -338,6 +338,24 @@ void registerMyObjectPeer(const QString & path, QDBusConnection::RegisterOptions QDBusMessage reply = QDBusConnection::sessionBus().call(req); } +void syncPeer() +{ + static int counter = 0; + QString reqId = QString::number(++counter); + + // wait for the sync signal with the right ID + QEventLoop loop; + QDBusConnection con("peer"); + con.connect(serviceName, objectPath, interfaceName, "syncReceived", + QStringList() << reqId, QString(), &loop, SLOT(quit())); + + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "requestSync"); + req << reqId; + QDBusConnection::sessionBus().send(req); + + loop.exec(); +} + void emitSignalPeer(const QString &interface, const QString &name, const QVariant ¶meter) { if (parameter.isValid()) @@ -1159,6 +1177,8 @@ void tst_QDBusAbstractAdaptor::signalEmissionsPeer() // connect all signals and emit only one { + syncPeer(); + QDBusSignalSpy spy; con.connect(QString(), "/", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); @@ -1186,6 +1206,8 @@ void tst_QDBusAbstractAdaptor::signalEmissionsPeer() // connect one signal and emit them all { + syncPeer(); + QDBusSignalSpy spy; con.connect(QString(), "/", interface, name, &spy, SLOT(slot(QDBusMessage))); emitSignalPeer("local.Interface2", "signal", QVariant()); @@ -1214,6 +1236,7 @@ void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer() registerMyObjectPeer("/p1"); registerMyObjectPeer("/p2"); + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); emitSignalPeer("local.Interface2", QString(), QVariant()); @@ -1241,6 +1264,7 @@ void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer() registerMyObjectPeer("/p1"); registerMyObjectPeer("/p2", 0); // don't export anything + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); @@ -1263,6 +1287,7 @@ void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer() registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); registerMyObjectPeer("/p2", 0); // don't export anything + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(QString(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); @@ -1286,6 +1311,7 @@ void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer() registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals | QDBusConnection::ExportNonScriptableSignals); + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); @@ -1338,6 +1364,7 @@ void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() // connect all signals and emit only one { + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/", "local.Interface4", "signal", "", &spy, SLOT(slot(QDBusMessage))); @@ -1358,6 +1385,7 @@ void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() QFETCH(QString, signature); // connect one signal and emit them all { + syncPeer(); QDBusSignalSpy spy; con.connect(QString(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage))); emitSignalPeer("local.Interface4", "signal", QVariant()); From c28045b118dcc139992ab5cd5028b94980942080 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 2 Sep 2014 08:23:06 -0700 Subject: [PATCH 090/323] Fix warnings about size conversion in QList Because difference_type is 64-bit on 64-bit systems, there's a downconversion warning from MSVC and possibly other compilers when it gets passed to functions taking simply int. Task-number: QTBUG-41092 Change-Id: I46a710810f4a57b8b84c4933f419a1f1fdf6bb5a Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- src/corelib/tools/qlist.cpp | 20 ++++++++++---------- src/corelib/tools/qlist.h | 23 +++++++++++++---------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 8e2bed7a7c..fe5e0f33b4 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -1363,7 +1363,7 @@ void **QListData::erase(void **xi) \sa operator*() */ -/*! \fn T &QList::iterator::operator[](int j) const +/*! \fn T &QList::iterator::operator[](difference_type j) const Returns a modifiable reference to the item at position *this + \a{j}. @@ -1464,7 +1464,7 @@ void **QListData::erase(void **xi) current and returns an iterator to the previously current item. */ -/*! \fn QList::iterator &QList::iterator::operator+=(int j) +/*! \fn QList::iterator &QList::iterator::operator+=(difference_type j) Advances the iterator by \a j items. (If \a j is negative, the iterator goes backward.) @@ -1472,7 +1472,7 @@ void **QListData::erase(void **xi) \sa operator-=(), operator+() */ -/*! \fn QList::iterator &QList::iterator::operator-=(int j) +/*! \fn QList::iterator &QList::iterator::operator-=(difference_type j) Makes the iterator go back by \a j items. (If \a j is negative, the iterator goes forward.) @@ -1480,7 +1480,7 @@ void **QListData::erase(void **xi) \sa operator+=(), operator-() */ -/*! \fn QList::iterator QList::iterator::operator+(int j) const +/*! \fn QList::iterator QList::iterator::operator+(difference_type j) const Returns an iterator to the item at \a j positions forward from this iterator. (If \a j is negative, the iterator goes backward.) @@ -1488,7 +1488,7 @@ void **QListData::erase(void **xi) \sa operator-(), operator+=() */ -/*! \fn QList::iterator QList::iterator::operator-(int j) const +/*! \fn QList::iterator QList::iterator::operator-(difference_type j) const Returns an iterator to the item at \a j positions backward from this iterator. (If \a j is negative, the iterator goes forward.) @@ -1618,7 +1618,7 @@ void **QListData::erase(void **xi) \sa operator*() */ -/*! \fn const T &QList::const_iterator::operator[](int j) const +/*! \fn const T &QList::const_iterator::operator[](difference_type j) const Returns the item at position *this + \a{j}. @@ -1710,7 +1710,7 @@ void **QListData::erase(void **xi) current and returns an iterator to the previously current item. */ -/*! \fn QList::const_iterator &QList::const_iterator::operator+=(int j) +/*! \fn QList::const_iterator &QList::const_iterator::operator+=(difference_type j) Advances the iterator by \a j items. (If \a j is negative, the iterator goes backward.) @@ -1718,7 +1718,7 @@ void **QListData::erase(void **xi) \sa operator-=(), operator+() */ -/*! \fn QList::const_iterator &QList::const_iterator::operator-=(int j) +/*! \fn QList::const_iterator &QList::const_iterator::operator-=(difference_type j) Makes the iterator go back by \a j items. (If \a j is negative, the iterator goes forward.) @@ -1726,7 +1726,7 @@ void **QListData::erase(void **xi) \sa operator+=(), operator-() */ -/*! \fn QList::const_iterator QList::const_iterator::operator+(int j) const +/*! \fn QList::const_iterator QList::const_iterator::operator+(difference_type j) const Returns an iterator to the item at \a j positions forward from this iterator. (If \a j is negative, the iterator goes backward.) @@ -1734,7 +1734,7 @@ void **QListData::erase(void **xi) \sa operator-(), operator+=() */ -/*! \fn QList::const_iterator QList::const_iterator::operator-(int j) const +/*! \fn QList::const_iterator QList::const_iterator::operator-(difference_type j) const Returns an iterator to the item at \a j positions backward from this iterator. (If \a j is negative, the iterator goes forward.) diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 326a276f40..e33be9a2f1 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -188,6 +188,7 @@ public: public: Node *i; typedef std::random_access_iterator_tag iterator_category; + // ### Qt6: use int typedef qptrdiff difference_type; typedef T value_type; typedef T *pointer; @@ -198,7 +199,7 @@ public: inline iterator(const iterator &o): i(o.i){} inline T &operator*() const { return i->t(); } inline T *operator->() const { return &i->t(); } - inline T &operator[](int j) const { return i[j].t(); } + inline T &operator[](difference_type j) const { return i[j].t(); } inline bool operator==(const iterator &o) const { return i == o.i; } inline bool operator!=(const iterator &o) const { return i != o.i; } inline bool operator<(const iterator& other) const { return i < other.i; } @@ -223,10 +224,10 @@ public: inline iterator operator++(int) { Node *n = i; ++i; return n; } inline iterator &operator--() { i--; return *this; } inline iterator operator--(int) { Node *n = i; i--; return n; } - inline iterator &operator+=(int j) { i+=j; return *this; } - inline iterator &operator-=(int j) { i-=j; return *this; } - inline iterator operator+(int j) const { return iterator(i+j); } - inline iterator operator-(int j) const { return iterator(i-j); } + inline iterator &operator+=(difference_type j) { i+=j; return *this; } + inline iterator &operator-=(difference_type j) { i-=j; return *this; } + inline iterator operator+(difference_type j) const { return iterator(i+j); } + inline iterator operator-(difference_type j) const { return iterator(i-j); } inline int operator-(iterator j) const { return int(i - j.i); } }; friend class iterator; @@ -235,6 +236,7 @@ public: public: Node *i; typedef std::random_access_iterator_tag iterator_category; + // ### Qt6: use int typedef qptrdiff difference_type; typedef T value_type; typedef const T *pointer; @@ -250,7 +252,7 @@ public: #endif inline const T &operator*() const { return i->t(); } inline const T *operator->() const { return &i->t(); } - inline const T &operator[](int j) const { return i[j].t(); } + inline const T &operator[](difference_type j) const { return i[j].t(); } inline bool operator==(const const_iterator &o) const { return i == o.i; } inline bool operator!=(const const_iterator &o) const { return i != o.i; } inline bool operator<(const const_iterator& other) const { return i < other.i; } @@ -261,10 +263,10 @@ public: inline const_iterator operator++(int) { Node *n = i; ++i; return n; } inline const_iterator &operator--() { i--; return *this; } inline const_iterator operator--(int) { Node *n = i; i--; return n; } - inline const_iterator &operator+=(int j) { i+=j; return *this; } - inline const_iterator &operator-=(int j) { i-=j; return *this; } - inline const_iterator operator+(int j) const { return const_iterator(i+j); } - inline const_iterator operator-(int j) const { return const_iterator(i-j); } + inline const_iterator &operator+=(difference_type j) { i+=j; return *this; } + inline const_iterator &operator-=(difference_type j) { i-=j; return *this; } + inline const_iterator operator+(difference_type j) const { return const_iterator(i+j); } + inline const_iterator operator-(difference_type j) const { return const_iterator(i-j); } inline int operator-(const_iterator j) const { return int(i - j.i); } }; friend class const_iterator; @@ -316,6 +318,7 @@ public: typedef const value_type *const_pointer; typedef value_type &reference; typedef const value_type &const_reference; + // ### Qt6: use int typedef qptrdiff difference_type; // comfort From 41ba4b3956d3c2f92277db090689833506d811b0 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 30 Oct 2014 10:23:34 +0100 Subject: [PATCH 091/323] QShapedPixmapWindow: do not leak the backing store Change-Id: Id7cc8cbbcd62c546055d525473f90d2bad0c144a Reviewed-by: Laszlo Agocs Reviewed-by: Friedemann Kleint --- src/gui/kernel/qshapedpixmapdndwindow.cpp | 6 ++++++ src/gui/kernel/qshapedpixmapdndwindow_p.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp index 55a8aae33c..af60b36647 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow.cpp +++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp @@ -52,6 +52,12 @@ QShapedPixmapWindow::QShapedPixmapWindow() m_backingStore = new QBackingStore(this); } +QShapedPixmapWindow::~QShapedPixmapWindow() +{ + delete m_backingStore; + m_backingStore = 0; +} + void QShapedPixmapWindow::render() { QRect rect(QPoint(), geometry().size()); diff --git a/src/gui/kernel/qshapedpixmapdndwindow_p.h b/src/gui/kernel/qshapedpixmapdndwindow_p.h index b59305f055..04198c83cb 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow_p.h +++ b/src/gui/kernel/qshapedpixmapdndwindow_p.h @@ -56,6 +56,7 @@ class QShapedPixmapWindow : public QWindow Q_OBJECT public: QShapedPixmapWindow(); + ~QShapedPixmapWindow(); void render(); From 85ea2434b101bd8c3674bc7a564eca1a3f57127a Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Fri, 31 Oct 2014 09:52:04 +0100 Subject: [PATCH 092/323] Cocoa plugin - fix a resource leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch 916dfcb8275bcce6b39606cd0b930239a60dc5df while fixing one problem, introduced another - leaking CGImage. Change-Id: I08db6ea9fa97ae3489a0bfa1f93e0d18f3671885 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qnsview.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index d109ce1db6..fa85a2bf54 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -589,6 +589,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; CGContextRestoreGState(cgContext); CGImageRelease(cleanImg); CGImageRelease(subMask); + CGImageRelease(bsCGImage); [self invalidateWindowShadowIfNeeded]; } From 7245599a8c7102de04a41a995b19e37ed7f1b7f0 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 14 Oct 2014 12:12:13 +0200 Subject: [PATCH 093/323] Handle mounts under /run We shouldn't excluded all volumes under /run since some distos will mount filesystems there. Instead we should exclude all filesystems with the type "tmpfs" that /run has, and rpc_pipefs that is mounted below /run. Tmpfs" is excluded for all UNIX systems since the BSDs have a similarly named filesystem. Change-Id: I03fdac515c0bfb1b824b2e3eae1022dd699c0998 Reviewed-by: Thiago Macieira --- src/corelib/io/qstorageinfo_unix.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 481de6ee38..e82737c51c 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -90,17 +90,16 @@ static bool isPseudoFs(const QString &mountDir, const QByteArray &type) { if (mountDir.startsWith(QLatin1String("/dev")) || mountDir.startsWith(QLatin1String("/proc")) - || mountDir.startsWith(QLatin1String("/run")) || mountDir.startsWith(QLatin1String("/sys")) || mountDir.startsWith(QLatin1String("/var/run")) || mountDir.startsWith(QLatin1String("/var/lock"))) { return true; } -#if defined(Q_OS_LINUX) - if (type == "rootfs") + if (type == "tmpfs") + return true; +#if defined(Q_OS_LINUX) + if (type == "rootfs" || type == "rpc_pipefs") return true; -#else - Q_UNUSED(type); #endif return false; From e76b0c05f2c0f0376157aa1ef5fdc5d718248d98 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 30 Oct 2014 16:42:15 +0100 Subject: [PATCH 094/323] Windows: Create touch device in initialization. Previously, the device was delay-created, which is a problem if its type is to be used for determinining the pan gesture type. Task-number: QTBUG-40461 Change-Id: I2dee3d7a3786a0fdf0a9b2b9e174dd121697ab44 Reviewed-by: Shawn Rutledge Reviewed-by: Laszlo Agocs --- .../platforms/windows/qwindowscontext.cpp | 11 +----- .../windows/qwindowsmousehandler.cpp | 37 ++++++++++++++----- .../platforms/windows/qwindowsmousehandler.h | 2 + 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index db48e0ed93..22a4dbb09f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -102,15 +102,6 @@ static inline int componentVerbose(const char *v, const char *keyWord) return 0; } -static inline bool hasTouchSupport(QSysInfo::WinVersion wv) -{ - enum { QT_SM_DIGITIZER = 94, QT_NID_INTEGRATED_TOUCH = 0x1, - QT_NID_EXTERNAL_TOUCH = 0x02, QT_NID_MULTI_INPUT = 0x40 }; - - return wv < QSysInfo::WV_WINDOWS7 ? false : - (GetSystemMetrics(QT_SM_DIGITIZER) & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH | QT_NID_MULTI_INPUT)) != 0; -} - #if !defined(LANG_SYRIAC) # define LANG_SYRIAC 0x5a #endif @@ -318,7 +309,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() QWindowsContext::shell32dll.init(); QWindowsContext::shcoredll.init(); - if (hasTouchSupport(ver) && QWindowsContext::user32dll.initTouch()) + if (m_mouseHandler.touchDevice() && QWindowsContext::user32dll.initTouch()) m_systemInfo |= QWindowsContext::SI_SupportsTouch; #endif // !Q_OS_WINCE m_displayContext = GetDC(0); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 39321c3460..acb692579b 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -109,6 +109,30 @@ static inline void compressMouseMove(MSG *msg) } } +static inline QTouchDevice *createTouchDevice() +{ + enum { QT_SM_TABLETPC = 86, QT_SM_DIGITIZER = 94, QT_SM_MAXIMUMTOUCHES = 95, + QT_NID_INTEGRATED_TOUCH = 0x1, QT_NID_EXTERNAL_TOUCH = 0x02, + QT_NID_MULTI_INPUT = 0x40, QT_NID_READY = 0x80 }; + + if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS7) + return 0; + const int digitizers = GetSystemMetrics(QT_SM_DIGITIZER); + if (!(digitizers & (QT_NID_INTEGRATED_TOUCH | QT_NID_EXTERNAL_TOUCH))) + return 0; + const int tabletPc = GetSystemMetrics(QT_SM_TABLETPC); + const int maxTouchPoints = GetSystemMetrics(QT_SM_MAXIMUMTOUCHES); + qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~QT_NID_READY) + << "Ready:" << (digitizers & QT_NID_READY) << dec << noshowbase + << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints; + QTouchDevice *result = new QTouchDevice; + result->setType(digitizers & QT_NID_INTEGRATED_TOUCH + ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad); + result->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition); + result->setMaximumTouchPoints(maxTouchPoints); + return result; +} + /*! \class QWindowsMouseHandler \brief Windows mouse handler @@ -122,10 +146,12 @@ static inline void compressMouseMove(MSG *msg) QWindowsMouseHandler::QWindowsMouseHandler() : m_windowUnderMouse(0), m_trackedWindow(0), - m_touchDevice(0), + m_touchDevice(createTouchDevice()), m_leftButtonDown(false), m_previousCaptureWindow(0) { + if (m_touchDevice) + QWindowSystemInterface::registerTouchDevice(m_touchDevice); } Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons() @@ -404,6 +430,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, typedef QWindowSystemInterface::TouchPoint QTouchPoint; typedef QList QTouchPointList; + Q_ASSERT(m_touchDevice); const QRect screenGeometry = window->screen()->geometry(); const int winTouchPointCount = msg.wParam; @@ -464,14 +491,6 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, if (allStates == Qt::TouchPointReleased) m_touchInputIDToTouchPointID.clear(); - if (!m_touchDevice) { - m_touchDevice = new QTouchDevice; - // TODO: Device used to be hardcoded to screen in previous code. - m_touchDevice->setType(QTouchDevice::TouchScreen); - m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(m_touchDevice); - } - QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 967c64e597..6491de93b5 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -51,6 +51,8 @@ class QWindowsMouseHandler public: QWindowsMouseHandler(); + QTouchDevice *touchDevice() const { return m_touchDevice; } + bool translateMouseEvent(QWindow *widget, HWND hwnd, QtWindows::WindowsEventType t, MSG msg, LRESULT *result); From f0b7abf2ef723432b387dfc5e0706675a9447133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Wed, 22 Oct 2014 15:17:41 +0200 Subject: [PATCH 095/323] Lower QVariant::userType call count We know that type id can't be changed, let pass this information to the compiler. Change-Id: I105b460417288b84250a954571c247608976f8f7 Reviewed-by: Stephen Kelly --- src/corelib/kernel/qvariant.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 57e0523f7c..7dce813bb5 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -703,14 +703,15 @@ namespace QtPrivate { { static QSequentialIterable invoke(const QVariant &v) { - if (v.userType() == qMetaTypeId()) { + const int typeId = v.userType(); + if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } - if (v.userType() == qMetaTypeId()) { + if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } #ifndef QT_BOOTSTRAPPED - if (v.userType() == qMetaTypeId()) { + if (typeId == qMetaTypeId()) { return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast(v.constData()))); } #endif @@ -722,10 +723,11 @@ namespace QtPrivate { { static QAssociativeIterable invoke(const QVariant &v) { - if (v.userType() == qMetaTypeId()) { + const int typeId = v.userType(); + if (typeId == qMetaTypeId()) { return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); } - if (v.userType() == qMetaTypeId()) { + if (typeId == qMetaTypeId()) { return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast(v.constData()))); } return QAssociativeIterable(v.value()); @@ -736,7 +738,8 @@ namespace QtPrivate { { static QVariantList invoke(const QVariant &v) { - if (QtMetaTypePrivate::isBuiltinSequentialType(v.userType()) || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId())) { + const int typeId = v.userType(); + if (QtMetaTypePrivate::isBuiltinSequentialType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) { QSequentialIterable iter = QVariantValueHelperInterface::invoke(v); QVariantList l; l.reserve(iter.size()); @@ -752,7 +755,8 @@ namespace QtPrivate { { static QVariantHash invoke(const QVariant &v) { - if (QtMetaTypePrivate::isBuiltinAssociativeType(v.userType()) || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId())) { + const int typeId = v.userType(); + if (QtMetaTypePrivate::isBuiltinAssociativeType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) { QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); QVariantHash l; l.reserve(iter.size()); @@ -768,7 +772,8 @@ namespace QtPrivate { { static QVariantMap invoke(const QVariant &v) { - if (QtMetaTypePrivate::isBuiltinAssociativeType(v.userType()) || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId())) { + const int typeId = v.userType(); + if (QtMetaTypePrivate::isBuiltinAssociativeType(typeId) || QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) { QAssociativeIterable iter = QVariantValueHelperInterface::invoke(v); QVariantMap l; for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it) @@ -783,10 +788,11 @@ namespace QtPrivate { { static QPair invoke(const QVariant &v) { - if (v.userType() == qMetaTypeId >()) + const int typeId = v.userType(); + if (typeId == qMetaTypeId >()) return QVariantValueHelper >::invoke(v); - if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId())) { + if (QMetaType::hasRegisteredConverterFunction(typeId, qMetaTypeId())) { QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value(); const QtMetaTypePrivate::VariantData d1 = pi.first(); From 08b1afc8f436f5221165fc074a9cab8f8a06bd67 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 31 Oct 2014 12:27:34 +0100 Subject: [PATCH 096/323] Mark QMetaMethod and related constructor as constepxr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtdelcarative's qquickaccessibleattached.cpp contains now some static instance of QMetaMethod. Marking the constructor as constexpr, let GCC to remove call to the constructor at load time. Change-Id: Ic5ab7db0d06caa08f15d65d3bb5f22a34a111fee Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qmetaobject.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 47a39a033d..2a874697c3 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -47,7 +47,7 @@ template class QList; class Q_CORE_EXPORT QMetaMethod { public: - inline QMetaMethod() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(0),handle(0) {} QByteArray methodSignature() const; QByteArray name() const; @@ -175,7 +175,7 @@ inline bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2) class Q_CORE_EXPORT QMetaEnum { public: - inline QMetaEnum() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaEnum() : mobj(0),handle(0) {} const char *name() const; bool isFlag() const; @@ -253,7 +253,7 @@ private: class Q_CORE_EXPORT QMetaClassInfo { public: - inline QMetaClassInfo() : mobj(0),handle(0) {} + Q_DECL_CONSTEXPR inline QMetaClassInfo() : mobj(0),handle(0) {} const char *name() const; const char *value() const; inline const QMetaObject *enclosingMetaObject() const { return mobj; } From 8cce08fbf914f949009eddda589c64a55925d733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 16 Oct 2014 14:46:55 +0200 Subject: [PATCH 097/323] iOS: Make sure we update hints and platform data on IM enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: If4d9c9c769b598a3194a7cd5bbe5c74e7650694b Reviewed-by: Richard Moe Gustavsen Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosinputcontext.mm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index b403154321..70307f7f54 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -443,6 +443,15 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) // Mask for properties that we are interested in and see if any of them changed updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImPlatformData); + if (updatedProperties & Qt::ImEnabled) { + // Switching on and off input-methods needs a re-fresh of hints and platform + // data when we turn them on again, as the IM state we have may have been + // invalidated when IM was switched off. We could defer this until we know + // if IM was turned on, to limit the extra query parameters, but for simplicity + // we always do the update. + updatedProperties |= (Qt::ImHints | Qt::ImPlatformData); + } + Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties); if (changedProperties & (Qt::ImEnabled | Qt::ImHints | Qt::ImPlatformData)) { // Changes to enablement or hints require virtual keyboard reconfigure From 6336ae831dcbe287e5aeeb73dc160bd067e63176 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 25 Jul 2014 23:08:27 -0700 Subject: [PATCH 098/323] Enable the latest versions of GCC, Clang and ICC with -Werror Tested with GCC 4.9, Clang from XCode 5.1 and ICC 15 beta. Clang 3.5 (pre-release) cannot compile qtdeclarative yet with -Werror due to invalid C++ code there that calls member functions on null pointers. Change-Id: Ic2845371a1899716985bc0813dfb820fa418e207 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- mkspecs/features/qt_common.prf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf index ebc5f00b8f..af9d6cae67 100644 --- a/mkspecs/features/qt_common.prf +++ b/mkspecs/features/qt_common.prf @@ -44,20 +44,20 @@ warnings_are_errors:warning_clean { # This setting is compiler-dependent anyway because it depends on the version of the # compiler. clang { - # Apple clang 4.0-4.2,5.0 + # Apple clang 4.0-4.2,5.0-5.1 # Regular clang 3.3 & 3.4 apple_ver = $${QT_APPLE_CLANG_MAJOR_VERSION}.$${QT_APPLE_CLANG_MINOR_VERSION} reg_ver = $${QT_CLANG_MAJOR_VERSION}.$${QT_CLANG_MINOR_VERSION} - contains(apple_ver, "4\\.[012]|5\\.0")|contains(reg_ver, "3\\.[34]") { + contains(apple_ver, "4\\.[012]|5\\.[01]")|contains(reg_ver, "3\\.[34]") { QMAKE_CXXFLAGS_WARN_ON += -Werror -Wno-error=\\$${LITERAL_HASH}warnings -Wno-error=deprecated-declarations $$WERROR # glibc's bswap_XX macros use the "register" keyword linux:equals(reg_ver, "3.4"): QMAKE_CXXFLAGS_WARN_ON += -Wno-error=deprecated-register } } else:intel_icc:linux { - # Intel CC 13.0 - 14.0, on Linux only + # Intel CC 13.0 - 15.0, on Linux only ver = $${QT_ICC_MAJOR_VERSION}.$${QT_ICC_MINOR_VERSION} - linux:contains(ver, "(13\\.|14\\.0)") { + linux:contains(ver, "(1[34]\\.|15\\.0)") { # 177: function "entity" was declared but never referenced # (too aggressive; ICC reports even for functions created due to template instantiation) # 1224: #warning directive @@ -67,9 +67,9 @@ warnings_are_errors:warning_clean { QMAKE_CXXFLAGS_WARN_ON += -Werror -ww177,1224,1478,1881 $$WERROR } } else:gcc:!clang:!intel_icc { - # GCC 4.6-4.8 + # GCC 4.6-4.9 ver = $${QT_GCC_MAJOR_VERSION}.$${QT_GCC_MINOR_VERSION} - contains(ver, "4\\.[678]") { + contains(ver, "4\\.[6789]") { QMAKE_CXXFLAGS_WARN_ON += -Werror -Wno-error=cpp -Wno-error=deprecated-declarations $$WERROR # GCC prints this bogus warning, after it has inlined a lot of code From 17e5b577b0a18d0612ddce3d8f26a09049b38a15 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 28 Mar 2014 13:54:13 +0100 Subject: [PATCH 099/323] Cleanup: Remove some obsolete code supporting a pre-4.3 format Loading a dock window state saved by a Qt 4.2 app is not something we need to support anymore. Change-Id: I9ee6e2c742b31114081852e7236cfc8696b9b270 Reviewed-by: Paul Olav Tvete --- src/widgets/widgets/qmainwindowlayout.cpp | 20 +++++------------- src/widgets/widgets/qmainwindowlayout_p.h | 2 +- src/widgets/widgets/qtoolbararealayout.cpp | 24 ++++++++-------------- src/widgets/widgets/qtoolbararealayout_p.h | 2 +- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 43f168ecd8..1cc7f201ba 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -615,11 +615,8 @@ static QList findChildrenHelper(const QObject *o) } //pre4.3 tests the format that was used before 4.3 -bool QMainWindowLayoutState::checkFormat(QDataStream &stream, bool pre43) +bool QMainWindowLayoutState::checkFormat(QDataStream &stream) { -#ifdef QT_NO_TOOLBAR - Q_UNUSED(pre43); -#endif while (!stream.atEnd()) { uchar marker; stream >> marker; @@ -630,8 +627,7 @@ bool QMainWindowLayoutState::checkFormat(QDataStream &stream, bool pre43) case QToolBarAreaLayout::ToolBarStateMarkerEx: { QList toolBars = findChildrenHelper(mainWindow); - if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, - pre43 /*testing 4.3 format*/, true /*testing*/)) { + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, true /*testing*/)) { return false; } } @@ -672,14 +668,8 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream, } QDataStream ds(copy); - const bool oldFormat = !checkFormat(ds, false); - if (oldFormat) { - //we should try with the old format - QDataStream ds2(copy); - if (!checkFormat(ds2, true)) { - return false; //format unknown - } - } + if (!checkFormat(ds)) + return false; QDataStream stream(copy); @@ -719,7 +709,7 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream, case QToolBarAreaLayout::ToolBarStateMarkerEx: { QList toolBars = findChildrenHelper(mainWindow); - if (!toolBarAreaLayout.restoreState(stream, toolBars, marker, oldFormat)) + if (!toolBarAreaLayout.restoreState(stream, toolBars, marker)) return false; for (int i = 0; i < toolBars.size(); ++i) { diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h index abec34af14..d9e18b03f4 100644 --- a/src/widgets/widgets/qmainwindowlayout_p.h +++ b/src/widgets/widgets/qmainwindowlayout_p.h @@ -133,7 +133,7 @@ public: QLayoutItem *unplug(const QList &path, QMainWindowLayoutState *savedState = 0); void saveState(QDataStream &stream) const; - bool checkFormat(QDataStream &stream, bool pre43); + bool checkFormat(QDataStream &stream); bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState); }; diff --git a/src/widgets/widgets/qtoolbararealayout.cpp b/src/widgets/widgets/qtoolbararealayout.cpp index 5494d49232..1dd39174ac 100644 --- a/src/widgets/widgets/qtoolbararealayout.cpp +++ b/src/widgets/widgets/qtoolbararealayout.cpp @@ -1286,21 +1286,15 @@ void QToolBarAreaLayout::saveState(QDataStream &stream) const } } -static inline int getInt(QDataStream &stream, Qt::Orientation o, bool pre43) +static inline int getInt(QDataStream &stream) { - if (pre43) { - QPoint p; - stream >> p; - return pick(o, p); - } else { - int x; - stream >> x; - return x; - } + int x; + stream >> x; + return x; } -bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList &_toolBars, uchar tmarker, bool pre43, bool testing) +bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList &_toolBars, uchar tmarker, bool testing) { QList toolBars = _toolBars; int lines; @@ -1325,8 +1319,8 @@ bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList> objectName; uchar shown; stream >> shown; - item.pos = getInt(stream, dock.o, pre43); - item.size = getInt(stream, dock.o, pre43); + item.pos = getInt(stream); + item.size = getInt(stream); /* 4.3.0 added floating toolbars, but failed to add the ability to restore them. @@ -1339,9 +1333,9 @@ bool QToolBarAreaLayout::restoreState(QDataStream &stream, const QList &path, QToolBarAreaLayout *other); void saveState(QDataStream &stream) const; - bool restoreState(QDataStream &stream, const QList &toolBars, uchar tmarker, bool pre43, bool testing = false); + bool restoreState(QDataStream &stream, const QList &toolBars, uchar tmarker, bool testing = false); bool isEmpty() const; }; From 9572dec3d72582bf99266af00a62028518d99852 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 31 Oct 2014 09:10:14 +0100 Subject: [PATCH 100/323] Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also fixes a compiler warning with clang Change-Id: I99beb7e099477b2b8b53af0e9fd32a7605a6c08a Reviewed-by: Jørgen Lind --- src/plugins/platforms/xcb/qglxintegration.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 84910c4172..5777980093 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -75,7 +75,6 @@ private: void init(QXcbScreen *screen, QPlatformOpenGLContext *share); void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle); - QXcbScreen *m_screen; Display *m_display; GLXFBConfig m_config; GLXContext m_context; From a8df9982901a8e9d01cce06c9ffe2b34e6ea23a7 Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Mon, 27 Oct 2014 23:09:06 +0100 Subject: [PATCH 101/323] Make QTestEventLoop::exitLoop() thread-safe QTestEventLoop::exitLoop() is used by QSignalSpy to stop event processing when the connected signal has been received. The design of QSignalSpy requires QTestEventLoop::exitLoop() to be thread-safe, which it wasn't. When QSignalSpy is connected to a signal in a different thread, exitLoop() was called from the thread which emitted the signal and not the one in which QTestEventLoop is running. This caused troubles when killing the internal timer. This patch adds a check in the beginning of exitLoop(). If it is called from a different thread, it will post an event into the message queue in which QTestEventLoop is running and execute it there. Change-Id: Icb8c8ff2f5344800ee6c6125b98c677c7a196c32 Reviewed-by: Thiago Macieira --- src/testlib/qtesteventloop.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/testlib/qtesteventloop.h b/src/testlib/qtesteventloop.h index 9e738d2c47..034655cc50 100644 --- a/src/testlib/qtesteventloop.h +++ b/src/testlib/qtesteventloop.h @@ -40,6 +40,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -101,6 +102,12 @@ inline void QTestEventLoop::enterLoopMSecs(int ms) inline void QTestEventLoop::exitLoop() { + if (thread() != QThread::currentThread()) + { + QMetaObject::invokeMethod(this, "exitLoop", Qt::QueuedConnection); + return; + } + if (timerId != -1) killTimer(timerId); timerId = -1; From 1b961e8b5d508d054e31c0050f27891606714393 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 29 Oct 2014 14:23:19 -0700 Subject: [PATCH 102/323] Fix compilation of with ICC and libc++ The libc++ header does this: #if !__has_feature(cxx_atomic) #error is not implemented So we can't enable the feature until the compiler reports true for that test. Change-Id: I96f1c7eea8b93d93bd721fe5a85fa987339d091f Reviewed-by: Olivier Goffart --- src/corelib/global/qcompilerdetection.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 8e52c50322..d7d5699591 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -881,6 +881,13 @@ # undef Q_COMPILER_RVALUE_REFS # undef Q_COMPILER_REF_QUALIFIERS # endif +# if defined(_LIBCPP_VERSION) +// libc++ uses __has_feature(cxx_atomic), so disable the feature if the compiler +// doesn't support it. That's required for the Intel compiler on OS X, for example. +# if !__has_feature(cxx_atomic) +# undef Q_COMPILER_ATOMICS +# endif +# endif # if defined(Q_COMPILER_THREADSAFE_STATICS) && defined(Q_OS_MAC) // Mac OS X: Apple's low-level implementation of the C++ support library // (libc++abi.dylib, shared between libstdc++ and libc++) has deadlocks. The From 1e9db9f5e18123f2e686c10b39b586caf1307729 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 29 Oct 2014 16:43:54 -0700 Subject: [PATCH 103/323] Enable C++11 atomics with Clang I don't know why it was an #if 0. The __has_feature has been there for a while. But, just to be sure, we check the presence of the header too. Change-Id: I36e34c9e8fd4ce55c98966d2fad246b77eb16597 Reviewed-by: Olivier Goffart --- src/corelib/global/qcompilerdetection.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index d7d5699591..949617fa7c 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -581,7 +581,7 @@ # define Q_COMPILER_ALIGNAS # define Q_COMPILER_ALIGNOF # endif -# if 0 /* not implemented in clang yet */ +# if __has_feature(cxx_atomic) && __has_include() # define Q_COMPILER_ATOMICS # endif # if __has_feature(cxx_attributes) @@ -880,6 +880,8 @@ # undef Q_COMPILER_INITIALIZER_LISTS # undef Q_COMPILER_RVALUE_REFS # undef Q_COMPILER_REF_QUALIFIERS +// Also disable , since it's clearly not there +# undef Q_COMPILER_ATOMICS # endif # if defined(_LIBCPP_VERSION) // libc++ uses __has_feature(cxx_atomic), so disable the feature if the compiler From 3b86bd5406d9e4b2a3778d5b4e16a371124afc80 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 29 Oct 2014 17:06:41 -0700 Subject: [PATCH 104/323] Reenable C++11 for ICC on OS X It's fixed for the Intel Composer XE 2015 (compiler version 15.0). Change-Id: I7960b2128743081e905d4b96acf55360f744fc69 Reviewed-by: Olivier Goffart --- mkspecs/macx-icc/qmake.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mkspecs/macx-icc/qmake.conf b/mkspecs/macx-icc/qmake.conf index a1783c97ad..09994b639f 100644 --- a/mkspecs/macx-icc/qmake.conf +++ b/mkspecs/macx-icc/qmake.conf @@ -52,8 +52,7 @@ QMAKE_CXXFLAGS_SHLIB = $$QMAKE_CFLAGS_SHLIB QMAKE_CXXFLAGS_STATIC_LIB = $$QMAKE_CFLAGS_STATIC_LIB QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD -# Disabled, due to invalid C++11 code on Apple headers -#QMAKE_CXXFLAGS_CXX11 = -std=c++11 +QMAKE_CXXFLAGS_CXX11 = -std=c++11 QMAKE_CXXFLAGS_SPLIT_SECTIONS = $$QMAKE_CFLAGS_SPLIT_SECTIONS QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG From 8cbbdae24c8c3cb0de015c2df3e27c20cb836083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Thu, 30 Oct 2014 16:05:46 +0100 Subject: [PATCH 105/323] Always invalidate the iOS accessibility cache This was observed in the weather app, where sometimes we could not find an items window. This could only be observed in the search results of the cities. (while VKB was visible). The old code traversed up to the QQuickListView and then it could not traversed further up in the parent hierarchy. Because of this it could also not find the associated window handle. The reason for this is unknown, but maybe it could be related to the fact that QQuickListView is a Component. Regardless of this, invalidate the cache should invalidate everything. We also traverse through all top level windows, but on iOS there should not be too many top level windows... Change-Id: I56a496435bb529a53d5ece8446cd2eeff502af84 Reviewed-by: Frederik Gladhorn --- .../ios/qiosplatformaccessibility.mm | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm index ad8bd9bdf4..705c626272 100644 --- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -58,16 +58,16 @@ void invalidateCache(QAccessibleInterface *iface) return; } - QWindow *win = 0; - QAccessibleInterface *parent = iface; - do { - win = parent->window(); - parent = parent->parent(); - } while (!win && parent); - - if (win && win->handle()) { - QIOSWindow *window = static_cast(win->handle()); - window->clearAccessibleCache(); + // This will invalidate everything regardless of what window the + // interface belonged to. We might want to revisit this strategy later. + // (Therefore this function still takes the interface as argument) + // It is also responsible for the bug that focus gets temporary lost + // when items get added or removed from the screen + foreach (QWindow *win, QGuiApplication::topLevelWindows()) { + if (win && win->handle()) { + QIOSWindow *window = static_cast(win->handle()); + window->clearAccessibleCache(); + } } } From e8d6d4f81c9aa34524938448c63b6e4beb7b1630 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 31 Oct 2014 11:36:04 +0100 Subject: [PATCH 106/323] QAndroidPlatformClipboard: fix build in release mode Q_ASSERT expands to nothing in release => mode unused. Change-Id: Ieb9ec4382e925250e1146239ce061763003ff6ba Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidplatformclipboard.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp index fb73db8455..2605ec9901 100644 --- a/src/plugins/platforms/android/qandroidplatformclipboard.cpp +++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp @@ -44,6 +44,7 @@ QAndroidPlatformClipboard::QAndroidPlatformClipboard() QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode) { + Q_UNUSED(mode); Q_ASSERT(supportsMode(mode)); m_mimeData.setText(QtAndroidClipboard::hasClipboardText() ? QtAndroidClipboard::clipboardText() @@ -53,8 +54,8 @@ QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode) void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) { - Q_ASSERT(supportsMode(mode)); - QtAndroidClipboard::setClipboardText(data != 0 && data->hasText() ? data->text() : QString()); + if (supportsMode(mode)) + QtAndroidClipboard::setClipboardText(data != 0 && data->hasText() ? data->text() : QString()); if (data != 0) data->deleteLater(); } From e0676a954c3a8375b30e6eb76450e2222de12079 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Thu, 7 Aug 2014 13:04:48 +0200 Subject: [PATCH 107/323] Add rpath pointing to Qt libraries in OS X and iOS This is triggered only when app is using Qt and Qt was built with "rpath" configuration and project does not specify QMAKE_RPATHDIR explicitly. Added rpath is made relative to app binary location if target path lies inside Qt SDK, so all SDK bundled tools and examples will work automatically without any changes. Tests are an exception here, since they are being run from their build location by CI, we may not use relative rpath that work only in install location. Task-number: QTBUG-31814 Change-Id: I3690f29d2b5396a19c1dbc92ad05e6c028f8515b Reviewed-by: Jake Petroules --- mkspecs/features/mac/default_post.prf | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mkspecs/features/mac/default_post.prf b/mkspecs/features/mac/default_post.prf index 530683552b..246c9c60e6 100644 --- a/mkspecs/features/mac/default_post.prf +++ b/mkspecs/features/mac/default_post.prf @@ -35,6 +35,30 @@ qt:!isEmpty(QT_CONFIG) { QMAKE_LFLAGS += -stdlib=libstdc++ } } + # If Qt was built with shared libraries with rpath support and project does + # not specify own rpaths (including empty list) add one pointing to Qt + # libraries. This applies only to apps, since all loaded libraries inherit + # rpaths from current process executable. + else:!if(host_build:force_bootstrap):equals(TEMPLATE, app):!defined(QMAKE_RPATHDIR, var):contains(QT_CONFIG, rpath) { + # If app is outside of Qt SDK prefix use absolute path to Qt libraries, + # otherwise make it relative, so all SDK tools and examples work when + # relocated. + # Tests are an exception, since they are launched in their build not + # install location by CI, so we cannot use relative rpaths there. + if(!contains(target.path, "$$re_escape($$[QT_INSTALL_PREFIX])/.*")|\ + contains(target.path, "$$re_escape($$[QT_INSTALL_TESTS])/.*")) { + QMAKE_RPATHDIR = $$[QT_INSTALL_LIBS] + } else { + app_bundle { + ios: binpath = $$target.path/$${TARGET}.app + else: binpath = $$target.path/$${TARGET}.app/Contents/MacOS + } else { + binpath = $$target.path + } + QMAKE_RPATHDIR = @loader_path/$$relative_path($$[QT_INSTALL_LIBS], $$binpath) + unset(binpath) + } + } } macx-xcode:!isEmpty(QMAKE_XCODE_DEBUG_INFORMATION_FORMAT) { From c0a54efc4091b365ffac09fc2827cf92f849d698 Mon Sep 17 00:00:00 2001 From: Adam Strzelecki Date: Wed, 6 Aug 2014 18:54:03 +0200 Subject: [PATCH 108/323] Build Qt for OS X and iOS with relative rpath Defaulting to absolute_library_soname on configure -rpath is no longer necessary as now we support @rpath install name ids on OS X and iOS. This also sets QMAKE_SONAME_PREFIX to @rpath for Qt modules when built with rpath configuration. This makes Qt libraries relocatable on OS X. Qt SDK is not yet relocatable though, because plugin location (including cocoa plugin) is still resolved using absolute path (see QTBUG-14150), also there are several absolute paths hardcoded in qmake mkspecs pri files. Task-number: QTBUG-31814 Change-Id: Ie9dffefcd2a946c1580293d433621c1adb7e06c4 Reviewed-by: Jake Petroules --- configure | 6 +----- mkspecs/features/qt_build_config.prf | 6 ------ mkspecs/features/qt_module.prf | 3 +++ 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 7d6ba9f4d6..1bd7db88b3 100755 --- a/configure +++ b/configure @@ -5783,11 +5783,7 @@ fi [ '!' -z "$INCLUDES" ] && QMakeVar add INCLUDEPATH "$INCLUDES" [ '!' -z "$L_FLAGS" ] && QMakeVar add LIBS "$L_FLAGS" -if [ "$XPLATFORM_MAC" = "yes" ] && [ "$QT_CROSS_COMPILE" = "no" ]; then - if [ "$CFG_RPATH" = "yes" ]; then - QMAKE_CONFIG="$QMAKE_CONFIG absolute_library_soname" - fi -elif [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then +if [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then if [ -n "$RPATH_FLAGS" ]; then echo echo "ERROR: -R cannot be used on this platform as \$QMAKE_LFLAGS_RPATH is" diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 42046c238a..7197f84c9a 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -52,12 +52,6 @@ QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR unset(modpath) } -mac { - !isEmpty(QMAKE_RPATHDIR){ - CONFIG += absolute_library_soname - } -} - cross_compile: \ CONFIG += force_bootstrap diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 8599a47ecd..7d47caef46 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -111,6 +111,9 @@ mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { } } +mac:contains(QT_CONFIG, rpath): \ + QMAKE_SONAME_PREFIX = @rpath + mac { CONFIG += explicitlib macx-g++ { From e8f223cf4850239276c6d56ec22810c81e82af74 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 30 Oct 2014 18:33:38 +0100 Subject: [PATCH 109/323] QMacStyle: More tweaks for editable QComboBox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note that at one point we need to use Cocoa to render the combo box, but only if we're dealing with Qt Quick controls. Also worth noticing, there's currently a bug in Cocoa when rendering inactive combob boxes. We faithfully reproduce it in Qt for now. We'll fix it when Apple does. Finally, we need to start constraininig the combo boxes height. Cocoa has not supported variable height combo boxes for years, and will even spit the following warning if we try to do something smart. This application is trying to draw a very large combo box, 28 points tall. Vertically resizable combo boxes are not supported, but it happens that 10.4 and previous drew something that looked kind of sort of okay. The art in 10.5 does not break up in a way that supports that drawing. This application should be revised to stop using large combo boxes. This warning will appear once per app launch. Task-number: QTBUG-40833 Task-number: QTBUG-42067 Change-Id: I6512a6a581d446a28585db22fe4dbeac09499321 Reviewed-by: Morten Johan Sørvig --- src/widgets/styles/qmacstyle_mac.mm | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 21ecdbc034..00112a5c6d 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -1921,6 +1921,8 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const offset = QPoint(2, 1); else if (widget == QCocoaWidget(QCocoaPullDownButton, QAquaSizeMini)) offset = QPoint(5, 0); + else if (widget == QCocoaWidget(QCocoaComboBox, QAquaSizeLarge)) + offset = QPoint(3, 0); QMacCGContext ctx(p); CGContextSaveGState(ctx); @@ -5733,14 +5735,20 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex break; case CC_ComboBox: if (const QStyleOptionComboBox *combo = qstyleoption_cast(opt)){ + const bool usingYosemiteOrLater = QSysInfo::MacintoshVersion > QSysInfo::MV_10_9; HIThemeButtonDrawInfo bdi; - d->initComboboxBdi(combo, &bdi, widget, d->getDrawState(opt->state)); + d->initComboboxBdi(combo, &bdi, widget, tds); HIRect rect = qt_hirectForQRect(combo->rect); - if (combo->editable && QSysInfo::MacintoshVersion > QSysInfo::MV_10_9) + if (combo->editable && usingYosemiteOrLater) rect.origin.y += tds == kThemeStateInactive ? 1 : 2; if (tds != kThemeStateInactive) QMacStylePrivate::drawCombobox(rect, bdi, p); - else + else if (!widget && combo->editable && usingYosemiteOrLater) { + QCocoaWidget cw = cocoaWidgetFromHIThemeButtonKind(bdi.kind); + NSView *cb = d->cocoaControl(cw); + QRect r = combo->rect.adjusted(3, 0, 0, 0); + d->drawNSViewInRect(cw, cb, r, p, widget != 0); + } else d->drawColorlessButton(rect, &bdi, p, opt); } break; @@ -6278,6 +6286,8 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op switch (sc) { case SC_ComboBoxEditField:{ ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); + if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_9) + ret.setHeight(ret.height() - 1); break; } case SC_ComboBoxArrow:{ ret = QMacStylePrivate::comboboxEditBounds(combo->rect, bdi); @@ -6715,10 +6725,13 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz.rwidth() += 10; sz.rheight() += 10; return sz; - case CT_ComboBox: + case CT_ComboBox: { sz.rwidth() += 50; - sz.rheight() += 2; + const QStyleOptionComboBox *cb = qstyleoption_cast(opt); + if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_10 || (cb && !cb->editable)) + sz.rheight() += 2; break; + } case CT_Menu: { QStyleHintReturnMask menuMask; QStyleOption myOption = *opt; From 627b70d768014c7a928b506bcf6a3c8e76a9fe76 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 30 Oct 2014 21:56:20 -0700 Subject: [PATCH 110/323] Fix warning caught by Clang on Linux qglxintegration.h:78:17: error: private field 'm_screen' is not used [-Werror,-Wunused-private-field] Change-Id: I7ffeda1dd4be962a4bfb43ebd3aa1dbd969a9837 Reviewed-by: Laszlo Agocs From 1ef505d01859be910de796c58a2b42636c6bc7da Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 30 Oct 2014 11:36:47 +0100 Subject: [PATCH 111/323] Fix warning about unused variable in qprintengine_win.cpp. qglobal.h:979:34: warning: unused variable 'q' [-Wunused-variable] ^ kernel\qprintengine_win.cpp:719:5: note: in expansion of macro 'Q_Q' Change-Id: I7fbad6c8341a3df1a06d3914209dec22876a2f09 Reviewed-by: Andy Shaw --- src/printsupport/kernel/qprintengine_win.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 90b204eb0c..7f5e83c61e 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -716,8 +716,6 @@ void QWin32PrintEnginePrivate::fillPath_dev(const QPainterPath &path, const QCol void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QColor &color, qreal penWidth) { - Q_Q(QWin32PrintEngine); - composeGdiPath(path); LOGBRUSH brush; brush.lbStyle = BS_SOLID; From 1b80e7a9d3f4f67597c6987c291f4c1b6adaf4a5 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Sat, 1 Nov 2014 21:29:44 +0100 Subject: [PATCH 112/323] Store clipboard before exiting native GTK dialog Gtk library usually takes care of this when the main Gtk loop ends, but since Gtk's main even loop is not used in QGtk2Dialog we have to store clipboard's content with help of gtk_clipboard_store(). This function sends a SAVE_TARGETS request to X11 clipboard manager to save clipboards contents as required by ICCCM. Task-number: QTBUG-34475 Change-Id: If784c425ea4a36ec1c3a8ddc0cdec080f57681a5 Reviewed-by: Shawn Rutledge Reviewed-by: Giuseppe D'Angelo --- src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp index c5f8338dab..d7e73c873d 100644 --- a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp +++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp @@ -82,6 +82,7 @@ QGtk2Dialog::QGtk2Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget) QGtk2Dialog::~QGtk2Dialog() { + gtk_clipboard_store(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD)); gtk_widget_destroy(gtkWidget); } From a31ad5b73ad31402c0dc89ce913b032c35bab79d Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Fri, 31 Oct 2014 16:09:23 +0100 Subject: [PATCH 113/323] WinRT: Set WindowTitle in application switcher Add platform backend for QWinRTWindow::setWindowTitle. Task-number: QTBUG-40736 Change-Id: I0b03c9b5977368b38ba63044b00178c3f2bb0b86 Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtwindow.cpp | 27 ++++++++++++++++++++ src/plugins/platforms/winrt/qwinrtwindow.h | 1 + 2 files changed, 28 insertions(+) diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 35d6b64008..8800db60d3 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -40,6 +40,14 @@ #include #include +#include +#include +#include + +using namespace ABI::Windows::UI::ViewManagement; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + QT_BEGIN_NAMESPACE QWinRTWindow::QWinRTWindow(QWindow *window) @@ -48,6 +56,7 @@ QWinRTWindow::QWinRTWindow(QWindow *window) { setWindowFlags(window->flags()); setWindowState(window->windowState()); + setWindowTitle(window->title()); handleContentOrientationChange(window->contentOrientation()); setGeometry(window->geometry()); } @@ -94,6 +103,24 @@ void QWinRTWindow::setVisible(bool visible) m_screen->removeWindow(window()); } +void QWinRTWindow::setWindowTitle(const QString &title) +{ + ComPtr statics; + HRESULT hr; + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + IID_PPV_ARGS(&statics)); + RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); + + ComPtr view; + hr = statics->GetForCurrentView(&view); + RETURN_VOID_IF_FAILED("Could not access currentView"); + + HStringReference str(reinterpret_cast(title.utf16()), title.length()); + hr = view->put_Title(str.Get()); + RETURN_VOID_IF_FAILED("Unable to set window title"); +} + void QWinRTWindow::raise() { if (!window()->isTopLevel()) diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 85f3efab5d..7e01efa818 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -52,6 +52,7 @@ public: bool isExposed() const; void setGeometry(const QRect &rect); void setVisible(bool visible); + void setWindowTitle(const QString &title); void raise(); void lower(); From 9571e0b6cd1f563a3155041a864a3922ed340664 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 10 Oct 2014 14:29:40 +0200 Subject: [PATCH 114/323] Doc: corrected autolink issue animation Task-number: QTBUG-40362 Change-Id: If89a8ae6aeecd4060a34f987baaf55c12439e7ea Reviewed-by: Frederik Gladhorn --- src/corelib/animation/qanimationgroup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp index 0f87d7263e..241501d60d 100644 --- a/src/corelib/animation/qanimationgroup.cpp +++ b/src/corelib/animation/qanimationgroup.cpp @@ -62,7 +62,7 @@ QAnimationGroup provides methods for adding and retrieving animations. Besides that, you can remove animations by calling - remove(), and clear the animation group by calling + \l removeAnimation(), and clear the animation group by calling clear(). You may keep track of changes in the group's animations by listening to QEvent::ChildAdded and QEvent::ChildRemoved events. From 30801d2d5cdb89c6b6133a7e61973ec8b91c60d1 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 28 Oct 2014 16:42:24 +0100 Subject: [PATCH 115/323] Doc: corrected wrong equivalent of obsolete QGraphicsItem::rotate Task-number: QTBUG-39027 Change-Id: Icb5998a4e28edbc6952bc79d970c5ce6dbe57d69 Reviewed-by: Andreas Aardal Hanssen --- src/widgets/graphicsview/qgraphicsitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 67d135271c..76a75dfc35 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -4487,7 +4487,7 @@ void QGraphicsItem::resetTransform() Use \code - setRotation(rotation() + angle); + item->setTransform(QTransform().rotate(angle), true); \endcode instead. From c998200282d5a6ce416aa8af9a6677fc2b1503af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Oct 2014 13:20:59 +0100 Subject: [PATCH 116/323] Don't build or use qt_convert_rgb888_to_rgb32_neon on ARM64/AArch64 The assembly code doesn't build on that architecture yet: qimage_neon.cpp:78:17: error: vector register expected "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t" ^ :1:15: note: instantiated into assembly here vld3.8 { d0, d1, d2 }, [x1] ! ^ qimage_neon.cpp:78:57: error: unrecognized instruction mnemonic "vld3.8 { d0, d1, d2 }, [%[SRC]] !\n\t" ^ :2:2: note: instantiated into assembly here vswp d0, d2 ^ qimage_neon.cpp:79:31: error: vector register expected "vswp d0, d2\n\t" ^ :3:15: note: instantiated into assembly here vst4.8 { d0, d1, d2, d3 }, [x8,:64] ! ^ Change-Id: I8fe93b3940d971c0aed5973fe6e1a5e2f362df3c Reviewed-by: Thiago Macieira --- src/gui/image/qimage_conversions.cpp | 2 +- src/gui/image/qimage_neon.cpp | 4 ++-- src/gui/image/qjpeghandler.cpp | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index bfa628900f..17563b19c3 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -2694,7 +2694,7 @@ void qInitImageConversions() } #endif -#ifdef __ARM_NEON__ +#if defined(__ARM_NEON__) && !defined(Q_PROCESSOR_ARM_64) extern void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags); qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_neon; qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_neon; diff --git a/src/gui/image/qimage_neon.cpp b/src/gui/image/qimage_neon.cpp index e3930bbb4d..88d1c87ee7 100644 --- a/src/gui/image/qimage_neon.cpp +++ b/src/gui/image/qimage_neon.cpp @@ -35,7 +35,7 @@ #include #include -#ifdef __ARM_NEON__ +#if defined(__ARM_NEON__) && !defined(Q_PROCESSOR_ARM_64) QT_BEGIN_NAMESPACE @@ -103,4 +103,4 @@ void convert_RGB888_to_RGB32_neon(QImageData *dest, const QImageData *src, Qt::I QT_END_NAMESPACE -#endif // __ARM_NEON__ +#endif // defined(__ARM_NEON__) && !defined(Q_PROCESSOR_ARM_64) diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp index 7ca8969798..87992bcced 100644 --- a/src/gui/image/qjpeghandler.cpp +++ b/src/gui/image/qjpeghandler.cpp @@ -1001,12 +1001,13 @@ extern "C" void qt_convert_rgb888_to_rgb32_mips_dspr2_asm(quint32 *dst, const uc QJpegHandler::QJpegHandler() : d(new QJpegHandlerPrivate(this)) { -#if defined(__ARM_NEON__) +#if defined(__ARM_NEON__) && !defined(Q_PROCESSOR_ARM_64) // from qimage_neon.cpp if (qCpuHasFeature(NEON)) rgb888ToRgb32ConverterPtr = qt_convert_rgb888_to_rgb32_neon; -#endif // __ARM_NEON__ +#endif + #if defined(QT_COMPILER_SUPPORTS_SSSE3) // from qimage_ssse3.cpp From 7a3a3a5694f9d20a759debf7a1fb8cb68b7d053b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 30 Oct 2014 19:44:11 +0100 Subject: [PATCH 117/323] Android: Add runOnUiThread() function Enables QRunnables to be run on the UI thread. For now this function is only intended for internal consumption. Change-Id: I5e2abb06104219a9dd55b3308113056e4da5fa07 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../org/qtproject/qt5/android/QtNative.java | 12 ++++++ src/corelib/kernel/qjnihelpers.cpp | 38 +++++++++++++++++++ src/corelib/kernel/qjnihelpers_p.h | 3 ++ 3 files changed, 53 insertions(+) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 51688441e0..0e0072d234 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -191,6 +191,16 @@ public class QtNative } } + private static void runQtOnUiThread(final long id) + { + runAction(new Runnable() { + @Override + public void run() { + QtNative.onAndroidUiThread(id); + } + }); + } + public static boolean startApplication(String params, String environment, String mainLibrary, @@ -618,4 +628,6 @@ public class QtNative // activity methods public static native void onActivityResult(int requestCode, int resultCode, Intent data); + + public static native void onAndroidUiThread(long id); } diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index c82b5ca033..d3bbce305a 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -34,6 +34,7 @@ #include "qjnihelpers_p.h" #include "qmutex.h" #include "qlist.h" +#include QT_BEGIN_NAMESPACE @@ -41,6 +42,19 @@ static JavaVM *g_javaVM = Q_NULLPTR; static jobject g_jActivity = Q_NULLPTR; static jobject g_jClassLoader = Q_NULLPTR; static jint g_androidSdkVersion = 0; +static jclass g_jNativeClass = Q_NULLPTR; +static jmethodID g_runQtOnUiThreadMethodID = Q_NULLPTR; + +static void onAndroidUiThread(JNIEnv *, jclass, jlong thiz) +{ + QRunnable *runnable = reinterpret_cast(thiz); + if (runnable == 0) + return; + + runnable->run(); + if (runnable->autoDelete()) + delete runnable; +} namespace { class ActivityResultListeners @@ -140,6 +154,22 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env) env->DeleteLocalRef(activity); g_javaVM = vm; + static const JNINativeMethod methods[] = { + {"onAndroidUiThread", "(J)V", reinterpret_cast(onAndroidUiThread)} + }; + + const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK); + + if (!regOk && exceptionCheck(env)) + return JNI_ERR; + + g_runQtOnUiThreadMethodID = env->GetStaticMethodID(jQtNative, + "runQtOnUiThread", + "(J)V"); + + g_jNativeClass = static_cast(env->NewGlobalRef(jQtNative)); + env->DeleteLocalRef(jQtNative); + return JNI_OK; } @@ -164,4 +194,12 @@ jint QtAndroidPrivate::androidSdkVersion() return g_androidSdkVersion; } +void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env) +{ + Q_ASSERT(runnable != 0); + env->CallStaticVoidMethod(g_jNativeClass, g_runQtOnUiThreadMethodID, reinterpret_cast(runnable)); + if (exceptionCheck(env) && runnable != 0 && runnable->autoDelete()) + delete runnable; +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h index 80c50ba611..6456dce4c4 100644 --- a/src/corelib/kernel/qjnihelpers_p.h +++ b/src/corelib/kernel/qjnihelpers_p.h @@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE +class QRunnable; + namespace QtAndroidPrivate { class Q_CORE_EXPORT ActivityResultListener @@ -64,6 +66,7 @@ namespace QtAndroidPrivate Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env); jobject classLoader(); Q_CORE_EXPORT jint androidSdkVersion(); + Q_CORE_EXPORT void runOnUiThread(QRunnable *runnable, JNIEnv *env); Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data); Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener); From 4835808287f88441975fa469420d4b64176cad82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 30 Oct 2014 19:43:32 +0100 Subject: [PATCH 118/323] Android: Simplify the jni code in QtAndroidInput Let the QJNI classes manager the jni environment and caching of jni handles. Change-Id: I8c238375026adf449d6e6e2b521caa6cd63a0fb4 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/android/androidjniinput.cpp | 59 ++++++------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index d2978dd48e..595892c1d1 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -48,10 +48,6 @@ using namespace QtAndroid; namespace QtAndroidInput { - static jmethodID m_showSoftwareKeyboardMethodID = 0; - static jmethodID m_resetSoftwareKeyboardMethodID = 0; - static jmethodID m_hideSoftwareKeyboardMethodID = 0; - static jmethodID m_updateSelectionMethodID = 0; static bool m_ignoreMouseEvents = false; static bool m_softwareKeyboardVisible = false; @@ -62,30 +58,28 @@ namespace QtAndroidInput void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd) { - AttachedJNIEnv env; - if (!env.jniEnv) - return; - #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd; #endif - env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID, - selStart, selEnd, candidatesStart, candidatesEnd); + QJNIObjectPrivate::callStaticMethod(applicationClass(), + "updateSelection", + "(IIII)V", + selStart, + selEnd, + candidatesStart, + candidatesEnd); } void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints) { - AttachedJNIEnv env; - if (!env.jniEnv) - return; - - env.jniEnv->CallStaticVoidMethod(applicationClass(), - m_showSoftwareKeyboardMethodID, - left, - top, - width, - height, - inputHints); + QJNIObjectPrivate::callStaticMethod(applicationClass(), + "showSoftwareKeyboard", + "(IIIII)V", + left, + top, + width, + height, + inputHints); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints; #endif @@ -93,11 +87,7 @@ namespace QtAndroidInput void resetSoftwareKeyboard() { - AttachedJNIEnv env; - if (!env.jniEnv) - return; - - env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "resetSoftwareKeyboard"); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ RESETSOFTWAREKEYBOARD"; #endif @@ -105,11 +95,7 @@ namespace QtAndroidInput void hideSoftwareKeyboard() { - AttachedJNIEnv env; - if (!env.jniEnv) - return; - - env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "hideSoftwareKeyboard"); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL qDebug() << "@@@ HIDESOFTWAREKEYBOARD"; #endif @@ -722,13 +708,6 @@ namespace QtAndroidInput {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged} }; -#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \ - VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \ - if (!VAR) { \ - __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \ - return false; \ - } - bool registerNatives(JNIEnv *env) { jclass appClass = QtAndroid::applicationClass(); @@ -738,10 +717,6 @@ namespace QtAndroidInput return false; } - GET_AND_CHECK_STATIC_METHOD(m_showSoftwareKeyboardMethodID, appClass, "showSoftwareKeyboard", "(IIIII)V"); - GET_AND_CHECK_STATIC_METHOD(m_resetSoftwareKeyboardMethodID, appClass, "resetSoftwareKeyboard", "()V"); - GET_AND_CHECK_STATIC_METHOD(m_hideSoftwareKeyboardMethodID, appClass, "hideSoftwareKeyboard", "()V"); - GET_AND_CHECK_STATIC_METHOD(m_updateSelectionMethodID, appClass, "updateSelection", "(IIII)V"); return true; } } From 078380df1e14ac82b3cf3ad66ae50d5351709537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Fri, 31 Oct 2014 14:11:01 +0100 Subject: [PATCH 119/323] Android: Simplify the jni code in QtAndroidMenu This is one of several fixes where the goal is to simplify the jni code by letting QJNI manage the environment. Change-Id: Ia714e25fbb3fcd170150392e822b0a3fc3812818 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/android/androidjnimenu.cpp | 27 ++++--------------- .../platforms/android/androidjnimenu.h | 2 +- .../android/qandroidplatformmenu.cpp | 3 ++- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp index ecd6fcce72..23182c6e57 100644 --- a/src/plugins/platforms/android/androidjnimenu.cpp +++ b/src/plugins/platforms/android/androidjnimenu.cpp @@ -44,6 +44,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -61,9 +62,6 @@ namespace QtAndroidMenu static QMutex menuBarMutex(QMutex::Recursive); static jmethodID openContextMenuMethodID = 0; - static jmethodID closeContextMenuMethodID = 0; - static jmethodID resetOptionsMenuMethodID = 0; - static jmethodID openOptionsMenuMethodID = 0; static jmethodID clearMenuMethodID = 0; static jmethodID addMenuItemMethodID = 0; @@ -78,16 +76,12 @@ namespace QtAndroidMenu void resetMenuBar() { - AttachedJNIEnv env; - if (env.jniEnv) - env.jniEnv->CallStaticVoidMethod(applicationClass(), resetOptionsMenuMethodID); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "resetOptionsMenu"); } void openOptionsMenu() { - AttachedJNIEnv env; - if (env.jniEnv) - env.jniEnv->CallStaticVoidMethod(applicationClass(), openOptionsMenuMethodID); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "openOptionsMenu"); } void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env) @@ -103,22 +97,14 @@ namespace QtAndroidMenu visibleMenu = menu; menu->aboutToShow(); - if (env) { - env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); - } else { - AttachedJNIEnv aenv; - if (aenv.jniEnv) - aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); - } + env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); } void hideContextMenu(QAndroidPlatformMenu *menu) { QMutexLocker lock(&visibleMenuMutex); if (visibleMenu == menu) { - AttachedJNIEnv env; - if (env.jniEnv) - env.jniEnv->CallStaticVoidMethod(applicationClass(), closeContextMenuMethodID); + QJNIObjectPrivate::callStaticMethod(applicationClass(), "closeContextMenu"); pendingContextMenus.clear(); } else { pendingContextMenus.removeOne(menu); @@ -430,9 +416,6 @@ namespace QtAndroidMenu } GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "(IIII)V"); - GET_AND_CHECK_STATIC_METHOD(closeContextMenuMethodID, appClass, "closeContextMenu", "()V"); - GET_AND_CHECK_STATIC_METHOD(resetOptionsMenuMethodID, appClass, "resetOptionsMenu", "()V"); - GET_AND_CHECK_STATIC_METHOD(openOptionsMenuMethodID, appClass, "openOptionsMenu", "()V"); jclass clazz; FIND_AND_CHECK_CLASS("android/view/Menu"); diff --git a/src/plugins/platforms/android/androidjnimenu.h b/src/plugins/platforms/android/androidjnimenu.h index c54eb37f37..f85db9ff86 100644 --- a/src/plugins/platforms/android/androidjnimenu.h +++ b/src/plugins/platforms/android/androidjnimenu.h @@ -50,7 +50,7 @@ namespace QtAndroidMenu { // Menu support void openOptionsMenu(); - void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env = 0); + void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env); void hideContextMenu(QAndroidPlatformMenu *menu); void syncMenu(QAndroidPlatformMenu *menu); void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu); diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp index f3505fac3c..8f992f6bea 100644 --- a/src/plugins/platforms/android/qandroidplatformmenu.cpp +++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp @@ -34,6 +34,7 @@ #include "qandroidplatformmenu.h" #include "qandroidplatformmenuitem.h" #include "androidjnimenu.h" +#include QT_BEGIN_NAMESPACE @@ -140,7 +141,7 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t Q_UNUSED(parentWindow); Q_UNUSED(item); setVisible(true); - QtAndroidMenu::showContextMenu(this, targetRect); + QtAndroidMenu::showContextMenu(this, targetRect, QJNIEnvironmentPrivate()); } QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const From 0df7ab1cabfd84c88b290cf784be6d51fb4f656a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 30 Oct 2014 19:23:40 +0100 Subject: [PATCH 120/323] Android: Remove AttachedJNIEnv class. The JNI environment should be managed by QJNIEnvironmentPrivate directly or through QJNIObjectPrivate. There is also a clear difference between calls coming from or going into Java code. Calls coming from Java already comes with the 'right' environment and in most cases no extra considerations or set-up is needed. Change-Id: I92d935ddfb70332041869185d5a92438930ff9b9 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/android/androidjnimain.cpp | 29 +++---------------- .../platforms/android/androidjnimain.h | 23 --------------- 2 files changed, 4 insertions(+), 48 deletions(-) diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 11f0bc5ffe..d1e78dfe5d 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -80,7 +80,6 @@ static jmethodID m_createBitmapMethodID = Q_NULLPTR; static jobject m_ARGB_8888_BitmapConfigValue = Q_NULLPTR; static jobject m_RGB_565_BitmapConfigValue = Q_NULLPTR; -jmethodID m_setFullScreenMethodID = Q_NULLPTR; static bool m_statusBarShowing = true; static jclass m_bitmapDrawableClass = Q_NULLPTR; @@ -182,13 +181,7 @@ namespace QtAndroid if (m_statusBarShowing) return; - QtAndroid::AttachedJNIEnv env; - if (!env.jniEnv) { - qWarning("Failed to get JNI Environment."); - return; - } - - env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, false); + QJNIObjectPrivate::callStaticMethod(m_applicationClass, "setFullScreen", "(Z)V", false); m_statusBarShowing = true; } @@ -197,13 +190,7 @@ namespace QtAndroid if (!m_statusBarShowing) return; - QtAndroid::AttachedJNIEnv env; - if (!env.jniEnv) { - qWarning("Failed to get JNI Environment."); - return; - } - - env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, true); + QJNIObjectPrivate::callStaticMethod(m_applicationClass, "setFullScreen", "(Z)V", true); m_statusBarShowing = false; } @@ -453,16 +440,9 @@ static void *startMainMethod(void */*data*/) if (res < 0) qWarning() << "dlclose failed:" << dlerror(); } - m_mainLibraryHnd = Q_NULLPTR; - m_main = Q_NULLPTR; - QtAndroid::AttachedJNIEnv env; - if (!env.jniEnv) - return 0; - if (m_applicationClass) { - jmethodID quitApp = env.jniEnv->GetStaticMethodID(m_applicationClass, "quitApp", "()V"); - env.jniEnv->CallStaticVoidMethod(m_applicationClass, quitApp); - } + if (m_applicationClass) + QJNIObjectPrivate::callStaticMethod(m_applicationClass, "quitApp", "()V"); return 0; } @@ -723,7 +703,6 @@ static int registerNatives(JNIEnv *env) jclass clazz; FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative"); m_applicationClass = static_cast(env->NewGlobalRef(clazz)); - GET_AND_CHECK_STATIC_METHOD(m_setFullScreenMethodID, m_applicationClass, "setFullScreen", "(Z)V"); if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed"); diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 01330ce283..8cf9274857 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -85,29 +85,6 @@ namespace QtAndroid jobject createBitmap(int width, int height, QImage::Format format, JNIEnv *env); jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0); - struct AttachedJNIEnv - { - AttachedJNIEnv() - { - attached = false; - if (QtAndroid::javaVM()->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) { - if (QtAndroid::javaVM()->AttachCurrentThread(&jniEnv, NULL) < 0) { - __android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed"); - jniEnv = Q_NULLPTR; - return; - } - attached = true; - } - } - - ~AttachedJNIEnv() - { - if (attached) - QtAndroid::javaVM()->DetachCurrentThread(); - } - bool attached; - JNIEnv *jniEnv; - }; const char *classErrorMsgFmt(); const char *methodErrorMsgFmt(); const char *qtTagText(); From d099e27cfc2885f28b36764f7c0917e5d708e778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 23 Oct 2014 15:24:25 +0200 Subject: [PATCH 121/323] Android: Fix input method hints. 1. Add comment about the magic TYPE_NUMBER_VARIATION_PASSWORD value. 2. ImhHiddenText, ImhNoPredictiveText and ImhSensitiveData should all disable suggestions. 3. Only ImhSensitiveData sets TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 4. Don't OR date and time to get DateTime... Task-number: QTBUG-38080 Change-Id: If456563983130e9af409ffa8cb717ddf259f1d6b Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/QtActivityDelegate.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 62a0263780..cab5da9dbc 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -265,30 +265,31 @@ public class QtActivityDelegate } if (Build.VERSION.SDK_INT > 10 && (inputHints & ImhHiddenText) != 0) - inputType |= 0x10; + inputType |= 0x10 /* TYPE_NUMBER_VARIATION_PASSWORD */; } else if ((inputHints & ImhDialableCharactersOnly) != 0) { inputType = android.text.InputType.TYPE_CLASS_PHONE; } else if ((inputHints & (ImhDate | ImhTime)) != 0) { inputType = android.text.InputType.TYPE_CLASS_DATETIME; - if ((inputHints & ImhDate) != 0) - inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE; - if ((inputHints & ImhTime) != 0) - inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME; + if ((inputHints & (ImhDate | ImhTime)) != (ImhDate | ImhTime)) { + if ((inputHints & ImhDate) != 0) + inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE; + if ((inputHints & ImhTime) != 0) + inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME; + } // else { TYPE_DATETIME_VARIATION_NORMAL(0) } } else { // CLASS_TEXT - if ((inputHints & ImhHiddenText) != 0) { + if ((inputHints & (ImhEmailCharactersOnly | ImhUrlCharactersOnly)) != 0) { + if ((inputHints & ImhUrlCharactersOnly) != 0) { + inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI; + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO; + } else if ((inputHints & ImhEmailCharactersOnly) != 0) { + inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; + } + } else if ((inputHints & ImhHiddenText) != 0) { inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD; - } else if ((inputHints & (ImhNoAutoUppercase | ImhNoPredictiveText | ImhSensitiveData)) != 0) { + } else if ((inputHints & ImhSensitiveData) != 0) { inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD; } - if ((inputHints & ImhEmailCharactersOnly) != 0) - inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS; - - if ((inputHints & ImhUrlCharactersOnly) != 0) { - inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI; - imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO; - } - if ((inputHints & ImhMultiLine) != 0) inputType |= android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE; @@ -300,8 +301,10 @@ public class QtActivityDelegate inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; } - if ((inputHints & ImhNoPredictiveText) != 0 || (inputHints & ImhSensitiveData) != 0) + if ((inputHints & ImhNoPredictiveText) != 0 || (inputHints & ImhSensitiveData) != 0 + || (inputHints & ImhHiddenText) != 0) { inputType |= android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; + } } if ((inputHints & ImhMultiLine) != 0) From 305f755d4b8d180ea2a4b40565bc327e550af5c5 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 3 Nov 2014 15:13:41 +0100 Subject: [PATCH 122/323] Regenerate qfiledialog_embedded.ui The old designer generator inserted stray spaces etc.; save it again with the new designer to fix those. Change-Id: I3890dd942970d9da71582ccb70b75d59888304bf Reviewed-by: Friedemann Kleint --- src/widgets/dialogs/qfiledialog_embedded.ui | 204 +++++++++++--------- 1 file changed, 108 insertions(+), 96 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog_embedded.ui b/src/widgets/dialogs/qfiledialog_embedded.ui index 16128dc0a0..69fc3255a1 100644 --- a/src/widgets/dialogs/qfiledialog_embedded.ui +++ b/src/widgets/dialogs/qfiledialog_embedded.ui @@ -1,4 +1,5 @@ - + + ********************************************************************* ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). @@ -40,8 +41,8 @@ ** ********************************************************************* QFileDialog - - + + 0 0 @@ -49,14 +50,14 @@ 320 - + true - + - - - + + + 1 0 @@ -64,45 +65,45 @@ - + - - + + Back - - + + Forward - - + + Parent Directory - - + + Create New Folder - - + + List View - - + + Detail View @@ -110,75 +111,86 @@ - - - + + + 0 0 - + Qt::Horizontal - - - + + + QFrame::NoFrame - + QFrame::Raised - - + + 0 - + + 0 + + + 0 + + + 0 + + 0 - - + + 0 - - - - 0 - 0 - 108 - 164 - - - - + + + 0 - + + 0 + + + 0 + + + 0 + + 0 - + - - - - 0 - 0 - 100 - 30 - - - - + + + 0 - + + 0 + + + 0 + + + 0 + + 0 - + @@ -189,31 +201,31 @@ - - - - - + + + + + 1 0 - - - + + + Qt::Vertical - + QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + + 0 0 @@ -223,23 +235,23 @@ - - + + false - - + + 0 0 - + 0 0 - + 0 0 @@ -248,45 +260,45 @@ - - + + false - - + + 0 0 - + 0 0 - + Files of type: - - + + false - - + + 0 0 - + 0 0 - + Look in: @@ -297,27 +309,27 @@ QFileDialogTreeView QTreeView -
qfiledialog_p.h
+
private/qfiledialog_p.h
QFileDialogListView QListView -
qfiledialog_p.h
+
private/qfiledialog_p.h
QSidebar QListWidget -
qsidebar_p.h
+
private/qsidebar_p.h
QFileDialogLineEdit QLineEdit -
qfiledialog_p.h
+
private/qfiledialog_p.h
QFileDialogComboBox QComboBox -
qfiledialog_p.h
+
private/qfiledialog_p.h
From d8b45a360f99149c42863067e3b40c619a892cd2 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 3 Nov 2014 15:14:46 +0100 Subject: [PATCH 123/323] QFileDialog: prevent section collapsing in the main selection area In the non-native QFileDialog, a QSplitter separates the two central views (the list view of "places" and the tree view for navigating the file system). Unfortunately, that splitter allows sections to be collapsed, resulting in a weird status where the user doesn't understand what has just happened and thinks that (s)he may have broken something. Worse, that gets actually saved into the application settings, so the splitter may stay collapsed forever. Instead, let's simply prevent sections from being collapsible. Task-number: QTBUG-19467 Change-Id: I11ff7c55a5535680a3edce5f4e70c9338291b94f Reviewed-by: Friedemann Kleint --- src/widgets/dialogs/qfiledialog.cpp | 2 +- src/widgets/dialogs/qfiledialog.ui | 3 +++ src/widgets/dialogs/qfiledialog_embedded.ui | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 0ba3ea40e0..6065ad015e 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -510,7 +510,7 @@ bool QFileDialog::restoreState(const QByteArray &state) if (!d->qFileDialogUi->splitter->restoreState(d->splitterState)) return false; QList list = d->qFileDialogUi->splitter->sizes(); - if (list.count() >= 2 && list.at(0) == 0 && list.at(1) == 0) { + if (list.count() >= 2 && (list.at(0) == 0 || list.at(1) == 0)) { for (int i = 0; i < list.count(); ++i) list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width(); d->qFileDialogUi->splitter->setSizes(list); diff --git a/src/widgets/dialogs/qfiledialog.ui b/src/widgets/dialogs/qfiledialog.ui index 89adaf530e..7f6e59c908 100644 --- a/src/widgets/dialogs/qfiledialog.ui +++ b/src/widgets/dialogs/qfiledialog.ui @@ -179,6 +179,9 @@ Qt::Horizontal + + false + Sidebar diff --git a/src/widgets/dialogs/qfiledialog_embedded.ui b/src/widgets/dialogs/qfiledialog_embedded.ui index 69fc3255a1..4cdc620437 100644 --- a/src/widgets/dialogs/qfiledialog_embedded.ui +++ b/src/widgets/dialogs/qfiledialog_embedded.ui @@ -121,6 +121,9 @@ Qt::Horizontal + + false + From d563f6142b9f319826ae68dbe630f1d865be29a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 22 Oct 2014 13:21:34 +0200 Subject: [PATCH 124/323] iOS: Make QIOSTextInputResponder a proper first-responder during text input Instead of faking it, by returning YES for isFirstResponder, which caused issues when iOS would try to dismiss the keyboard by resigning the true first-responder. Change-Id: I816c4cf9c699d72995ce7968e1f1a4aa9c9c167e Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosinputcontext.h | 8 ++- src/plugins/platforms/ios/qiosinputcontext.mm | 43 ++++++++++++--- .../platforms/ios/qiostextresponder.mm | 54 ++++++++++++++++++- src/plugins/platforms/ios/quiview.mm | 10 ++++ 4 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 8850bbf80e..46fe35d884 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -65,7 +65,8 @@ public: void showInputPanel(); void hideInputPanel(); - void hideVirtualKeyboard(); + + void clearCurrentFocusObject(); bool isInputPanelVisible() const; void setFocusObject(QObject *object); @@ -81,10 +82,15 @@ public: const ImeState &imeState() { return m_imeState; }; + bool isReloadingInputViewsFromUpdate() const { return m_isReloadingInputViewsFromUpdate; } + + static QIOSInputContext *instance(); + private: QIOSKeyboardListener *m_keyboardListener; QIOSTextInputResponder *m_textResponder; ImeState m_imeState; + bool m_isReloadingInputViewsFromUpdate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 70307f7f54..c038628fd9 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -44,6 +44,7 @@ #import #include "qiosglobal.h" +#include "qiosintegration.h" #include "qiostextresponder.h" #include "qioswindow.h" #include "quiview.h" @@ -206,7 +207,10 @@ static QUIView *focusView() CGPoint p = [[touches anyObject] locationInView:m_viewController.view.window]; if (CGRectContainsPoint(m_keyboardEndRect, p)) { m_keyboardHiddenByGesture = YES; - m_context->hideVirtualKeyboard(); + + UIResponder *firstResponder = [UIResponder currentFirstResponder]; + Q_ASSERT([firstResponder isKindOfClass:[QIOSTextInputResponder class]]); + [firstResponder resignFirstResponder]; } [super touchesMoved:touches withEvent:event]; @@ -279,10 +283,16 @@ Qt::InputMethodQueries ImeState::update(Qt::InputMethodQueries properties) // ------------------------------------------------------------------------- +QIOSInputContext *QIOSInputContext::instance() +{ + return static_cast(QIOSIntegration::instance()->inputContext()); +} + QIOSInputContext::QIOSInputContext() : QPlatformInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_textResponder(0) + , m_isReloadingInputViewsFromUpdate(false) { if (isQtApplication()) connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged); @@ -310,9 +320,10 @@ void QIOSInputContext::hideInputPanel() // No-op, keyboard controlled fully by platform based on focus } -void QIOSInputContext::hideVirtualKeyboard() +void QIOSInputContext::clearCurrentFocusObject() { - static_cast(QObjectPrivate::get(qApp->focusWindow()))->clearFocusObject(); + if (QWindow *focusWindow = qApp->focusWindow()) + static_cast(QObjectPrivate::get(focusWindow))->clearFocusObject(); } bool QIOSInputContext::isInputPanelVisible() const @@ -452,12 +463,24 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) updatedProperties |= (Qt::ImHints | Qt::ImPlatformData); } + qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); + Qt::InputMethodQueries changedProperties = m_imeState.update(updatedProperties); if (changedProperties & (Qt::ImEnabled | Qt::ImHints | Qt::ImPlatformData)) { // Changes to enablement or hints require virtual keyboard reconfigure - [m_textResponder release]; - m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this]; - [m_textResponder reloadInputViews]; + + qImDebug() << "changed IM properties" << changedProperties << "require keyboard reconfigure"; + + if (inputMethodAccepted()) { + qImDebug() << "replacing text responder with new text responder"; + [m_textResponder autorelease]; + m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this]; + [m_textResponder becomeFirstResponder]; + } else { + qImDebug() << "IM not enabled, reloading input views"; + QScopedValueRollback recursionGuard(m_isReloadingInputViewsFromUpdate, true); + [[UIResponder currentFirstResponder] reloadInputViews]; + } } else { [m_textResponder notifyInputDelegate:changedProperties]; } @@ -497,6 +520,12 @@ void QIOSInputContext::commit() @implementation QUIView (InputMethods) - (void)reloadInputViews { - qApp->inputMethod()->reset(); + if (QIOSInputContext::instance()->isReloadingInputViewsFromUpdate()) { + qImDebug() << "preventing recursion by reloading super"; + [super reloadInputViews]; + } else { + qImDebug() << "reseting input methods"; + qApp->inputMethod()->reset(); + } } @end diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 54362cde7a..b809fc4b51 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -218,11 +218,61 @@ [super dealloc]; } -- (BOOL)isFirstResponder +- (BOOL)canBecomeFirstResponder { return YES; } +- (BOOL)becomeFirstResponder +{ + FirstResponderCandidate firstResponderCandidate(self); + + qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder]; + + if (![super becomeFirstResponder]) { + qImDebug() << self << "was not allowed to become first responder"; + return NO; + } + + qImDebug() << self << "became first responder"; + + return YES; +} + +- (BOOL)resignFirstResponder +{ + qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder]; + + // Don't allow activation events of the window that we're doing text on behalf on + // to steal responder. + if (FirstResponderCandidate::currentCandidate() == [self nextResponder]) { + qImDebug() << "not allowing parent window to steal responder"; + return NO; + } + + if (![super resignFirstResponder]) + return NO; + + qImDebug() << self << "resigned first responder"; + + // Dismissing the keyboard will trigger resignFirstResponder, but so will + // a regular responder transfer to another window. In the former case, iOS + // will set the new first-responder to our next-responder, and in the latter + // case we'll have an active responder candidate. + if ([UIResponder currentFirstResponder] == [self nextResponder]) { + // We have resigned the keyboard, and transferred back to the parent view, so unset focus object + Q_ASSERT(!FirstResponderCandidate::currentCandidate()); + qImDebug() << "keyboard was closed, clearing focus object"; + m_inputContext->clearCurrentFocusObject(); + } else { + // We've lost responder status because another window was made active + Q_ASSERT(FirstResponderCandidate::currentCandidate()); + } + + return YES; +} + + - (UIResponder*)nextResponder { return qApp->focusWindow() ? @@ -577,7 +627,7 @@ Qt::InputMethodHints imeHints = static_cast([self imValue:Qt::ImHints].toUInt()); if (!(imeHints & Qt::ImhMultiLine)) - m_inputContext->hideVirtualKeyboard(); + [self resignFirstResponder]; return; } diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 33e5b955e3..c4b92618b1 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -44,6 +44,7 @@ #include "qiosglobal.h" #include "qiosintegration.h" #include "qiosviewcontroller.h" +#include "qiostextresponder.h" #include "qioswindow.h" #include "qiosmenu.h" @@ -222,6 +223,15 @@ if ([responder isKindOfClass:[QUIView class]]) return NO; + // Nor do we want to deactivate the Qt window if the new responder + // is temporarily handling text input on behalf of a Qt window. + if ([responder isKindOfClass:[QIOSTextInputResponder class]]) { + while ((responder = [responder nextResponder])) { + if ([responder isKindOfClass:[QUIView class]]) + return NO; + } + } + return YES; } From c432960718de8afb43512f35d5339b3a5b8ead2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 23 Oct 2014 14:28:06 +0200 Subject: [PATCH 125/323] iOS: Be more thorough when looking for current first responder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The technique of sending an action does not always end up at the actual first responder, but it will end up in a responder in the responder chain of the first responder, so we continue searching the subviews recursively until we find the real first-responder. Change-Id: I6abc9bc18eb127fa4b317cd308783c0ecfcd670a Reviewed-by: Richard Moe Gustavsen Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosglobal.mm | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index bc16a7997d..71d5a58088 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -152,6 +152,22 @@ int infoPlistValue(NSString* key, int defaultValue) @implementation QtFirstResponderEvent @end + +@implementation UIView (QtFirstResponder) +- (UIView*)qt_findFirstResponder +{ + if ([self isFirstResponder]) + return self; + + for (UIView *subview in self.subviews) { + if (UIView *firstResponder = [subview qt_findFirstResponder]) + return firstResponder; + } + + return nil; +} +@end + @implementation UIResponder (QtFirstResponder) +(id)currentFirstResponder @@ -164,7 +180,11 @@ int infoPlistValue(NSString* key, int defaultValue) - (void)qt_findFirstResponder:(id)sender event:(QtFirstResponderEvent *)event { Q_UNUSED(sender); - event.firstResponder = self; + + if ([self isKindOfClass:[UIView class]]) + event.firstResponder = [static_cast(self) qt_findFirstResponder]; + else + event.firstResponder = [self isFirstResponder] ? self : nil; } @end From c4cfe9091e4f2e4b3054718a4b876413b48e1563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Oct 2014 10:42:56 +0100 Subject: [PATCH 126/323] iOS: Allow virtual keyboard returnKeyType to be set through IM platformData The result of pressing the key is still a Qt::Key_Return press/release sequence, which needs to be handled manually. Change-Id: I72c7b0067bd3ec1bc315ab2c84361800b7be0943 Reviewed-by: Richard Moe Gustavsen Reviewed-by: Marius Bugge Monsen --- src/plugins/platforms/ios/qiosinputcontext.h | 1 + src/plugins/platforms/ios/qiostextresponder.mm | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 46fe35d884..5791367d84 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -42,6 +42,7 @@ const char kImePlatformDataInputView[] = "inputView"; const char kImePlatformDataInputAccessoryView[] = "inputAccessoryView"; +const char kImePlatformDataReturnKeyType[] = "returnKeyType"; QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index b809fc4b51..e3c73f5222 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -173,9 +173,13 @@ m_inSendEventToFocusObject = NO; m_inputContext = inputContext; + QVariantMap platformData = [self imValue:Qt::ImPlatformData].toMap(); Qt::InputMethodHints hints = Qt::InputMethodHints([self imValue:Qt::ImHints].toUInt()); - self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + self.returnKeyType = platformData.value(kImePlatformDataReturnKeyType).isValid() ? + UIReturnKeyType(platformData.value(kImePlatformDataReturnKeyType).toInt()) : + (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText); self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ? UITextAutocorrectionTypeNo : UITextAutocorrectionTypeDefault; @@ -202,7 +206,6 @@ else self.keyboardType = UIKeyboardTypeDefault; - QVariantMap platformData = [self imValue:Qt::ImPlatformData].toMap(); if (UIView *inputView = static_cast(platformData.value(kImePlatformDataInputView).value())) self.inputView = [[[WrapperView alloc] initWithView:inputView] autorelease]; if (UIView *accessoryView = static_cast(platformData.value(kImePlatformDataInputAccessoryView).value())) @@ -625,8 +628,7 @@ [self sendEventToFocusObject:press]; [self sendEventToFocusObject:release]; - Qt::InputMethodHints imeHints = static_cast([self imValue:Qt::ImHints].toUInt()); - if (!(imeHints & Qt::ImhMultiLine)) + if (self.returnKeyType == UIReturnKeyDone) [self resignFirstResponder]; return; From eab4bd5cee2faa78962184f7c04b03ec3383e3c7 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 3 Nov 2014 17:18:55 +0100 Subject: [PATCH 127/323] Fix a fatal Clang warning on Linux Two fromstrerror_helper overloads are defined, to manage the fact that strerror_r returns an int or a char* depending on the system. The problem is that then only one overload used (again, depending on the actual stderror_r return type), leading to one of the two overload to be unused and thus triggering the unused function warning. kernel/qsystemerror.cpp:64:27: error: unused function 'fromstrerror_helper' [-Werror,-Wunused-function] static inline QString fromstrerror_helper(int, const QByteArray &buf) Change-Id: I6a1c8e1a4b7d14068b682db26002ff68ad36167c Reviewed-by: Olivier Goffart --- src/corelib/kernel/qsystemerror.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp index 5c185e1d62..3b1d808520 100644 --- a/src/corelib/kernel/qsystemerror.cpp +++ b/src/corelib/kernel/qsystemerror.cpp @@ -61,11 +61,11 @@ namespace { // version in portable code. However, it's impossible to do that if // _GNU_SOURCE is defined so we use C++ overloading to decide what to do // depending on the return type - static inline QString fromstrerror_helper(int, const QByteArray &buf) + static inline Q_DECL_UNUSED QString fromstrerror_helper(int, const QByteArray &buf) { return QString::fromLocal8Bit(buf); } - static inline QString fromstrerror_helper(const char *str, const QByteArray &) + static inline Q_DECL_UNUSED QString fromstrerror_helper(const char *str, const QByteArray &) { return QString::fromLocal8Bit(str); } From cca4eb45c5e1a70d2c39cad2d77abf0b986bc087 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 3 Nov 2014 11:44:42 +0100 Subject: [PATCH 128/323] Windows: Ignore key Shift+F10 unless a shortcut is registered for it. This key combination should open the context menu. Task-number: QTBUG-40085 Change-Id: I7cfc89f766b3734b9fb9d3c9135b4896ffbadb5b Reviewed-by: Oliver Wolff Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/windows/qwindowskeymapper.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 990dbaeba2..ff9ad1874a 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -39,6 +39,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE @@ -1104,9 +1105,17 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms else { const QString text = uch.isNull() ? QString() : QString(uch); const char a = uch.row() ? 0 : uch.cell(); + const Qt::KeyboardModifiers modifiers(state); +#ifndef QT_NO_SHORTCUT + // Is Qt interested in the context menu key? + if (modifiers == Qt::SHIFT && code == Qt::Key_F10 + && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(QKeySequence(Qt::SHIFT + Qt::Key_F10))) { + return false; + } +#endif // !QT_NO_SHORTCUT key_recorder.storeKey(msg.wParam, a, state, text); QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code, - Qt::KeyboardModifier(state), scancode, msg.wParam, nModifiers, text, false); + modifiers, scancode, msg.wParam, nModifiers, text, false); result =true; bool store = true; #ifndef Q_OS_WINCE From dce44534850548eefb8f060e51869fe906ca5ad4 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 30 Oct 2014 10:22:36 +0100 Subject: [PATCH 129/323] Prevent a leak of QXcbXSettingsPrivate The private was not deleted. Adding the dtor in turn causes a warning about not having a virtual dtor in the base class, so add that as well. Change-Id: I24a90caf2cf6192a6f17cf5af96b8f77010d9127 Reviewed-by: Shawn Rutledge Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.h | 1 + src/plugins/platforms/xcb/qxcbxsettings.cpp | 6 ++++++ src/plugins/platforms/xcb/qxcbxsettings.h | 1 + 3 files changed, 8 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 51c7c91bf6..f31ecf8e03 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -324,6 +324,7 @@ private: class QXcbWindowEventListener { public: + virtual ~QXcbWindowEventListener() {} virtual bool handleGenericEvent(xcb_generic_event_t *, long *) { return false; } virtual void handleExposeEvent(const xcb_expose_event_t *) {} diff --git a/src/plugins/platforms/xcb/qxcbxsettings.cpp b/src/plugins/platforms/xcb/qxcbxsettings.cpp index 6f2e60c9be..13d42832db 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.cpp +++ b/src/plugins/platforms/xcb/qxcbxsettings.cpp @@ -262,6 +262,12 @@ QXcbXSettings::QXcbXSettings(QXcbScreen *screen) d_ptr->initialized = true; } +QXcbXSettings::~QXcbXSettings() +{ + delete d_ptr; + d_ptr = 0; +} + bool QXcbXSettings::initialized() const { Q_D(const QXcbXSettings); diff --git a/src/plugins/platforms/xcb/qxcbxsettings.h b/src/plugins/platforms/xcb/qxcbxsettings.h index 717fe559c9..3496cedf36 100644 --- a/src/plugins/platforms/xcb/qxcbxsettings.h +++ b/src/plugins/platforms/xcb/qxcbxsettings.h @@ -45,6 +45,7 @@ class QXcbXSettings : public QXcbWindowEventListener Q_DECLARE_PRIVATE(QXcbXSettings) public: QXcbXSettings(QXcbScreen *screen); + ~QXcbXSettings(); bool initialized() const; QVariant setting(const QByteArray &property) const; From 21e5d77e85ced10db6fe9c1bf2e0461195e1560c Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 20 Oct 2014 14:18:34 +0300 Subject: [PATCH 130/323] Android: Fix more exceptions in ExtractStyle.java on Android L Task-number: QTBUG-40120 Change-Id: I949f19ced4eefcf7a40e64ad63e316765c6f2f48 Reviewed-by: J-P Nurmi --- .../qtproject/qt5/android/ExtractStyle.java | 55 +++++++++++++++---- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 0eda08c9d9..b75dbac4b8 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -647,7 +647,8 @@ public class ExtractStyle { GradientDrawable.Orientation orientation=(Orientation) gradientStateClass.getField("mOrientation").get(obj); json.put("orientation",orientation.name()); int [] intArray=(int[]) gradientStateClass.getField("mColors").get(obj); - json.put("colors",getJsonArray(intArray, 0, intArray.length)); + if (intArray != null) + json.put("colors",getJsonArray(intArray, 0, intArray.length)); json.put("positions",getJsonArray((float[]) gradientStateClass.getField("mPositions").get(obj))); json.put("strokeWidth",gradientStateClass.getField("mStrokeWidth").getInt(obj)); json.put("strokeDashWidth",gradientStateClass.getField("mStrokeDashWidth").getFloat(obj)); @@ -1210,9 +1211,17 @@ public class ExtractStyle { json.put("TextView_drawableEnd", getDrawable(a.getDrawable(attr), styleName + "_TextView_drawableEnd", null)); else if (attr == TextView_drawablePadding) json.put("TextView_drawablePadding", a.getDimensionPixelSize(attr, 0)); - else if (attr == TextView_textCursorDrawable) - json.put("TextView_textCursorDrawable", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textCursorDrawable", null)); - else if (attr == TextView_maxLines) + else if (attr == TextView_textCursorDrawable) { + try { + json.put("TextView_textCursorDrawable", getDrawable(a.getDrawable(attr), styleName + "_TextView_textCursorDrawable", null)); + } catch (Exception e_) { + try { + json.put("TextView_textCursorDrawable", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textCursorDrawable", null)); + } catch (Exception e) { + e.printStackTrace(); + } + } + }else if (attr == TextView_maxLines) json.put("TextView_maxLines", a.getInt(attr, -1)); else if (attr == TextView_maxHeight) json.put("TextView_maxHeight", a.getDimensionPixelSize(attr, -1)); @@ -1300,13 +1309,37 @@ public class ExtractStyle { json.put("TextView_imeActionId", a.getInt(attr,0)); else if (attr == TextView_privateImeOptions) json.put("TextView_privateImeOptions", a.getString(attr)); - else if (attr == TextView_textSelectHandleLeft && styleName.equals("textViewStyle")) - json.put("TextView_textSelectHandleLeft", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleLeft", null)); - else if (attr == TextView_textSelectHandleRight && styleName.equals("textViewStyle")) - json.put("TextView_textSelectHandleRight", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleRight", null)); - else if (attr == TextView_textSelectHandle && styleName.equals("textViewStyle")) - json.put("TextView_textSelectHandle", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandle", null)); - else if (attr == TextView_textIsSelectable) + else if (attr == TextView_textSelectHandleLeft && styleName.equals("textViewStyle")) { + try { + json.put("TextView_textSelectHandleLeft", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandleLeft", null)); + } catch (Exception _e) { + try { + json.put("TextView_textSelectHandleLeft", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleLeft", null)); + } catch (Exception e) { + e.printStackTrace(); + } + } + } else if (attr == TextView_textSelectHandleRight && styleName.equals("textViewStyle")) { + try { + json.put("TextView_textSelectHandleRight", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandleRight", null)); + } catch (Exception _e) { + try { + json.put("TextView_textSelectHandleRight", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandleRight", null)); + } catch (Exception e) { + e.printStackTrace(); + } + } + } else if (attr == TextView_textSelectHandle && styleName.equals("textViewStyle")) { + try { + json.put("TextView_textSelectHandle", getDrawable(a.getDrawable(attr), styleName + "_TextView_textSelectHandle", null)); + } catch (Exception _e) { + try { + json.put("TextView_textSelectHandle", getDrawable(m_context.getResources().getDrawable(a.getResourceId(attr, 0)), styleName + "_TextView_textSelectHandle", null)); + } catch (Exception e) { + e.printStackTrace(); + } + } + } else if (attr == TextView_textIsSelectable) json.put("TextView_textIsSelectable", a.getBoolean(attr, false)); else if (attr == TextView_textAllCaps) allCaps = a.getBoolean(attr, false); From 01054603a797805cc5c18c65aed7f0f192b68851 Mon Sep 17 00:00:00 2001 From: Marko Kangas Date: Thu, 23 Oct 2014 10:27:02 +0300 Subject: [PATCH 131/323] Fix tab icon vertical alignment Fixes case if custom icon size is given and height is more than width. Check of minimum valid height was compared wrongly to width and caused invalid vertical alignment. After fix vertical alignment is correct aligned to vertical center with the tab text. Change-Id: I6c4a710b15e91225edeabb629bfea7049ab2f42a Task-number: QTBUG-42143 Reviewed-by: Timur Pocheptsov Reviewed-by: Jens Bache-Wiig --- src/widgets/styles/qcommonstyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index 8579308820..1c5dcf5f0a 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -1114,7 +1114,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTabV3 *opt, const QWidget (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled, (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off ); // High-dpi icons do not need adjustmet; make sure tabIconSize is not larger than iconSize - tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.width())); + tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height())); *iconRect = QRect(tr.left(), tr.center().y() - tabIconSize.height() / 2, tabIconSize.width(), tabIconSize .height()); From e8f1b9917008d978c29cda9a2b40b841bc7a9df4 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 20 Oct 2014 14:09:33 +0200 Subject: [PATCH 132/323] Don't delete QLibrarySettings configuration in ~QCoreApplication Do not clear the QLibrarySettings configuration information already in ~QCoreApplication (via qAddPostRoutine). This fixes issues where multiple QCoreApplication objects are created over time (in plugins). Task-number: QTBUG-34290 Change-Id: Ib5c58f825619ede484492e057e08d73b2b4c6101 Reviewed-by: Oswald Buddenhagen Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- src/corelib/global/qlibraryinfo.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index c3ec2bc7f6..7ca0aa7f0b 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -84,14 +84,7 @@ class QLibraryInfoPrivate { public: static QSettings *findConfiguration(); -#ifndef QT_BOOTSTRAPPED - static void cleanup() - { - QLibrarySettings *ls = qt_library_settings(); - if (ls) - ls->settings.reset(0); - } -#else +#ifdef QT_BOOTSTRAPPED static bool haveGroup(QLibraryInfo::PathGroup group) { QLibrarySettings *ls = qt_library_settings(); @@ -114,7 +107,6 @@ QLibrarySettings::QLibrarySettings() : settings(QLibraryInfoPrivate::findConfiguration()) { #ifndef QT_BOOTSTRAPPED - qAddPostRoutine(QLibraryInfoPrivate::cleanup); bool haveEffectivePaths; bool havePaths; #endif From 0d679261176aadb3dd8efdc8e130bcbe6f3ce6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 3 Nov 2014 17:41:04 +0100 Subject: [PATCH 133/323] Use __aarch64__ instead of __arm64__ to detect AArch64 The latter name was used by Apple in their internal AArch64 LLVM backend, but has since been merged into LLVM upstream and renamed to AArch64. https://github.com/llvm-mirror/llvm/commit/29f94c72014eaa5d0d3b920686e68 Change-Id: I319f42f07c95dfbcd121134fbe6e554e2d36453d Reviewed-by: Thiago Macieira --- src/corelib/global/qprocessordetection.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h index 26ac56396b..55cb31c62b 100644 --- a/src/corelib/global/qprocessordetection.h +++ b/src/corelib/global/qprocessordetection.h @@ -87,9 +87,9 @@ ARM is bi-endian, detect using __ARMEL__ or __ARMEB__, falling back to auto-detection implemented below. */ -#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(__arm64__) +#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(__aarch64__) # define Q_PROCESSOR_ARM -# if defined(__arm64__) +# if defined(__aarch64__) # define Q_PROCESSOR_ARM_64 # else # define Q_PROCESSOR_ARM_32 From f08ddefac7d4495c28370c84bf9b383d6cf3abd1 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Mon, 3 Nov 2014 15:52:04 +0100 Subject: [PATCH 134/323] Check the Q_SCRIPTABLE tag of signals and slots as early as possible. This makes is possible to generate a valid D-Bus XML from a class that has e.g. internal slots with pointer parameters by explicitly marking all D-Bus exports with Q_SCRIPTABLE and running qdbuscpp2xml with the '-a' switch. Change-Id: Iab32a0a7f46f2516f6385808bbf35b26c7708b1a Reviewed-by: Thiago Macieira --- src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp index ea24c35a07..dc735df297 100644 --- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp +++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp @@ -243,6 +243,8 @@ static QString generateInterfaceXml(const ClassDef *mo) foreach (const FunctionDef &mm, mo->signalList) { if (mm.wasCloned) continue; + if (!mm.isScriptable && !(flags & QDBusConnection::ExportNonScriptableSignals)) + continue; retval += addFunction(mm, true); } @@ -250,10 +252,14 @@ static QString generateInterfaceXml(const ClassDef *mo) if (flags & (QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportNonScriptableSlots)) { foreach (const FunctionDef &slot, mo->slotList) { + if (!slot.isScriptable && !(flags & QDBusConnection::ExportNonScriptableSlots)) + continue; if (slot.access == FunctionDef::Public) retval += addFunction(slot); } foreach (const FunctionDef &method, mo->methodList) { + if (!method.isScriptable && !(flags & QDBusConnection::ExportNonScriptableSlots)) + continue; if (method.access == FunctionDef::Public) retval += addFunction(method); } From 293207b50377eef2b8f2bec10a24eae02bcedc93 Mon Sep 17 00:00:00 2001 From: Venu Date: Tue, 4 Nov 2014 11:06:35 +0100 Subject: [PATCH 135/323] qdoc: Delayed the examples manifest file creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids the creation of demos-manifest.xml if there are no demos in the repo. Change-Id: I4d3bbe4540f4b1532c0d51f62b8d1494864a7b1c Reviewed-by: Martin Smith Reviewed-by: Topi Reiniö --- src/tools/qdoc/htmlgenerator.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 32399f11c7..5b8ccd9902 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -4301,8 +4301,6 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element) return; QString fileName = manifest +"-manifest.xml"; QFile file(outputDir() + QLatin1Char('/') + fileName); - if (!file.open(QFile::WriteOnly | QFile::Text)) - return ; bool demos = false; if (manifest == "demos") demos = true; @@ -4323,7 +4321,7 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element) } ++i; } - if (!proceed) + if (!proceed || !file.open(QFile::WriteOnly | QFile::Text)) return; QXmlStreamWriter writer(&file); From dce13e4b7b0d6cf04879fc3b1f2a241579296e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Wed, 22 Oct 2014 13:29:52 +0200 Subject: [PATCH 136/323] Fix too many resizes and move events for native widgets When the QWidgetWindow receives a resize or move event, it should check with the widget if its crect already has this geometry. if not then send the resize or move event Ideally events should be sent whenever the QWidgetWindow receives them. QTBUG-42383 is created for this problem Task-number: QTBUG-29937 Task-number: QTBUG-38768 Task-number: QTBUG-30744 Change-Id: I1e9a5d25de29a98885edece927ba14d7a763eb01 Reviewed-by: Shawn Rutledge --- src/widgets/dialogs/qwizard.cpp | 8 ++ src/widgets/kernel/qwidget.cpp | 5 +- src/widgets/kernel/qwidgetwindow.cpp | 53 ++++++--- src/widgets/kernel/qwidgetwindow_p.h | 4 +- .../qwidget_window/tst_qwidget_window.cpp | 101 ++++++++++++++++++ 5 files changed, 151 insertions(+), 20 deletions(-) mode change 100755 => 100644 tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp index 1f7b18e824..a378daa3d3 100644 --- a/src/widgets/dialogs/qwizard.cpp +++ b/src/widgets/dialogs/qwizard.cpp @@ -2571,6 +2571,14 @@ void QWizard::setWizardStyle(WizardStyle style) d->disableUpdates(); d->wizStyle = style; d->updateButtonTexts(); +#if !defined(QT_NO_STYLE_WINDOWSVISTA) + if (aeroStyleChange) { + //Send a resizeevent since the antiflicker widget probably needs a new size + //because of the backbutton in the window title + QResizeEvent ev(geometry().size(), geometry().size()); + QApplication::sendEvent(this, &ev); + } +#endif d->updateLayout(); updateGeometry(); d->enableUpdates(); diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index cc262fa3e2..315d615d89 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -7155,10 +7155,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) } } - // generate a move event for QWidgets without window handles. QWidgets with native - // window handles already receive a move event from - // QGuiApplicationPrivate::processGeometryChangeEvent. - if (isMove && (!q->windowHandle() || q->testAttribute(Qt::WA_DontShowOnScreen))) { + if (isMove) { QMoveEvent e(q->pos(), oldPos); QApplication::sendEvent(q, &e); } diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 1cd042f99d..e455b772fb 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -543,14 +543,36 @@ void QWidgetWindow::handleKeyEvent(QKeyEvent *event) QGuiApplication::sendSpontaneousEvent(receiver, event); } -void QWidgetWindow::updateGeometry() +bool QWidgetWindow::updateSize() { + bool changed = false; if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) - return; + return changed; + if (m_widget->data->crect.size() != geometry().size()) { + changed = true; + m_widget->data->crect.setSize(geometry().size()); + } + updateMargins(); + return changed; +} + +bool QWidgetWindow::updatePos() +{ + bool changed = false; + if (m_widget->testAttribute(Qt::WA_OutsideWSRange)) + return changed; + if (m_widget->data->crect.topLeft() != geometry().topLeft()) { + changed = true; + m_widget->data->crect.moveTopLeft(geometry().topLeft()); + } + updateMargins(); + return changed; +} + +void QWidgetWindow::updateMargins() +{ const QMargins margins = frameMargins(); - - m_widget->data->crect = geometry(); QTLWExtra *te = m_widget->d_func()->topData(); te->posIncludesFrame= false; te->frameStrut.setCoords(margins.left(), margins.top(), margins.right(), margins.bottom()); @@ -609,24 +631,25 @@ void QWidgetWindow::updateNormalGeometry() void QWidgetWindow::handleMoveEvent(QMoveEvent *event) { - updateGeometry(); - QGuiApplication::sendSpontaneousEvent(m_widget, event); + if (updatePos()) + QGuiApplication::sendSpontaneousEvent(m_widget, event); } void QWidgetWindow::handleResizeEvent(QResizeEvent *event) { QSize oldSize = m_widget->data->crect.size(); - updateGeometry(); - QGuiApplication::sendSpontaneousEvent(m_widget, event); + if (updateSize()) { + QGuiApplication::sendSpontaneousEvent(m_widget, event); - if (m_widget->d_func()->paintOnScreen()) { - QRegion updateRegion(geometry()); - if (m_widget->testAttribute(Qt::WA_StaticContents)) - updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height()); - m_widget->d_func()->syncBackingStore(updateRegion); - } else { - m_widget->d_func()->syncBackingStore(); + if (m_widget->d_func()->paintOnScreen()) { + QRegion updateRegion(geometry()); + if (m_widget->testAttribute(Qt::WA_StaticContents)) + updateRegion -= QRect(0, 0, oldSize.width(), oldSize.height()); + m_widget->d_func()->syncBackingStore(updateRegion); + } else { + m_widget->d_func()->syncBackingStore(); + } } } diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h index 7f12ae8e20..0632a5c364 100644 --- a/src/widgets/kernel/qwidgetwindow_p.h +++ b/src/widgets/kernel/qwidgetwindow_p.h @@ -108,7 +108,9 @@ private slots: private: void repaintWindow(); - void updateGeometry(); + bool updateSize(); + bool updatePos(); + void updateMargins(); void updateNormalGeometry(); enum FocusWidgets { diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp old mode 100755 new mode 100644 index c6c7464194..36791293ab --- a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp +++ b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp @@ -95,6 +95,8 @@ private slots: void tst_updateWinId_QTBUG40681(); void tst_recreateWindow_QTBUG40817(); + void tst_resize_count(); + void tst_move_count(); }; void tst_QWidget_window::initTestCase() @@ -660,6 +662,105 @@ void tst_QWidget_window::tst_recreateWindow_QTBUG40817() tab.setCurrentIndex(1); } +class ResizeWidget : public QWidget +{ +Q_OBJECT +public: + ResizeWidget(QWidget *parent = 0) + : QWidget(parent) + , resizeCount(0) + { } + + int resizeCount; + +protected: + void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE + { + resizeCount++; + } +}; + +void tst_QWidget_window::tst_resize_count() +{ + { + ResizeWidget resize; + resize.show(); + QVERIFY(QTest::qWaitForWindowExposed(&resize)); + QCOMPARE(resize.resizeCount, 1); + resize.resizeCount = 0; + QSize size = resize.size(); + size.rwidth() += 10; + resize.resize(size); + QGuiApplication::sync(); + QTRY_COMPARE(resize.resizeCount, 1); + + resize.resizeCount = 0; + + ResizeWidget child(&resize); + child.resize(200,200); + child.winId(); + child.show(); + QVERIFY(QTest::qWaitForWindowExposed(&child)); + QGuiApplication::sync(); + QTRY_COMPARE(child.resizeCount, 1); + child.resizeCount = 0; + size = child.size(); + size.rwidth() += 10; + child.resize(size); + QGuiApplication::sync(); + QCOMPARE(resize.resizeCount, 0); + QCOMPARE(child.resizeCount, 1); + } + { + ResizeWidget parent; + ResizeWidget child(&parent); + child.resize(200,200); + child.winId(); + parent.show(); + QVERIFY(QTest::qWaitForWindowExposed(&parent)); + parent.resizeCount = 0; + QGuiApplication::sync(); + QTRY_COMPARE(child.resizeCount, 1); + child.resizeCount = 0; + QSize size = child.size(); + size.rwidth() += 10; + child.resize(size); + QGuiApplication::sync(); + QCOMPARE(parent.resizeCount, 0); + QCOMPARE(child.resizeCount, 1); + } + +} + +class MoveWidget : public QWidget +{ +Q_OBJECT +public: + MoveWidget(QWidget *parent = 0) + : QWidget(parent) + , moveCount(0) + { } + + void moveEvent(QMoveEvent *) Q_DECL_OVERRIDE + { + moveCount++; + } + + int moveCount; +}; + +void tst_QWidget_window::tst_move_count() +{ + MoveWidget move; + move.move(500,500); + move.show(); + QVERIFY(QTest::qWaitForWindowExposed(&move)); + QTRY_VERIFY(move.moveCount >= 1); + move.moveCount = 0; + + move.move(220,250); + QTRY_VERIFY(move.moveCount >= 1); +} QTEST_MAIN(tst_QWidget_window) #include "tst_qwidget_window.moc" From 85a71381145528d446416d2744734384dbe739b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 4 Nov 2014 18:12:46 +0100 Subject: [PATCH 137/323] Define Q_CC_CLANG to be the version of upstream Clang that's in use We map the Apple Clang versions to upstream, so that we have one define to compare against. Fixes build break on iOS due to qbasicatomic.h not defining QT_BASIC_ATOMIC_HAS_CONSTRUCTORS on Apple Clang versions, which is needed after 1e9db9f5e18123f2e686c10b Change-Id: I17493c0187c20abc5d22e71944d62bfd16afbad2 Reviewed-by: Thiago Macieira --- src/corelib/global/qcompilerdetection.h | 25 ++++++++++++++++++++++--- src/corelib/thread/qbasicatomic.h | 10 +++------- src/corelib/tools/qsimd_p.h | 2 +- tests/auto/tools/moc/tst_moc.cpp | 2 +- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 949617fa7c..de8a53ea06 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -152,7 +152,26 @@ # endif # elif defined(__clang__) /* Clang also masquerades as GCC */ -# define Q_CC_CLANG +# if defined(__apple_build_version__) +# /* http://en.wikipedia.org/wiki/Xcode#Toolchain_Versions */ +# if __apple_build_version__ >= 600051 +# define Q_CC_CLANG 305 +# elif __apple_build_version__ >= 503038 +# define Q_CC_CLANG 304 +# elif __apple_build_version__ >= 500275 +# define Q_CC_CLANG 303 +# elif __apple_build_version__ >= 425024 +# define Q_CC_CLANG 302 +# elif __apple_build_version__ >= 318045 +# define Q_CC_CLANG 301 +# elif __apple_build_version__ >= 211101 +# define Q_CC_CLANG 300 +# else +# error "Unknown Apple Clang version" +# endif +# else +# define Q_CC_CLANG ((__clang_major__ * 100) + __clang_minor__) +# endif # define Q_ASSUME_IMPL(expr) if (expr){} else __builtin_unreachable() # define Q_UNREACHABLE_IMPL() __builtin_unreachable() # if !defined(__has_extension) @@ -566,7 +585,7 @@ # endif // Variadic macros are supported for gnu++98, c++11, c99 ... since 2.9 -# if ((__clang_major__ * 100) + __clang_minor__) >= 209 +# if Q_CC_CLANG >= 209 # if !defined(__STRICT_ANSI__) || defined(__GXX_EXPERIMENTAL_CXX0X__) \ || (defined(__cplusplus) && (__cplusplus >= 201103L)) \ || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) @@ -668,7 +687,7 @@ # define Q_COMPILER_VARIADIC_TEMPLATES # endif /* Features that have no __has_feature() check */ -# if ((__clang_major__ * 100) + __clang_minor__) >= 209 /* since clang 2.9 */ +# if Q_CC_CLANG >= 209 /* since clang 2.9 */ # define Q_COMPILER_EXTERN_TEMPLATES # endif # endif diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index 09500e92d7..be293f58e3 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -84,13 +84,9 @@ QT_END_NAMESPACE // New atomics #if defined(Q_COMPILER_CONSTEXPR) && defined(Q_COMPILER_DEFAULT_MEMBERS) && defined(Q_COMPILER_DELETE_MEMBERS) -# if defined(Q_CC_CLANG) && ((((__clang_major__ * 100) + __clang_minor__) < 303) \ - || defined(__apple_build_version__) \ - ) - /* Do not define QT_BASIC_ATOMIC_HAS_CONSTRUCTORS for "stock" clang before version 3.3. - Apple's version has different (higher!) version numbers, so disable it for all of them for now. - (The only way to distinguish between them seems to be a check for __apple_build_version__ .) - +# if defined(Q_CC_CLANG) && Q_CC_CLANG < 303 + /* + Do not define QT_BASIC_ATOMIC_HAS_CONSTRUCTORS for Clang before version 3.3. For details about the bug: see http://llvm.org/bugs/show_bug.cgi?id=12670 */ # else diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 434819aa61..3241e09b08 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -219,7 +219,7 @@ // other x86 intrinsics #if defined(Q_PROCESSOR_X86) && ((defined(Q_CC_GNU) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) \ - || (defined(Q_CC_CLANG) && (__clang_major__ * 100 + __clang_minor__ >= 208)) \ + || (defined(Q_CC_CLANG) && (Q_CC_CLANG >= 208)) \ || defined(Q_CC_INTEL)) # define QT_COMPILER_SUPPORTS_X86INTRIN # ifdef Q_CC_INTEL diff --git a/tests/auto/tools/moc/tst_moc.cpp b/tests/auto/tools/moc/tst_moc.cpp index 13e786cd20..edb6488eaa 100644 --- a/tests/auto/tools/moc/tst_moc.cpp +++ b/tests/auto/tools/moc/tst_moc.cpp @@ -1564,7 +1564,7 @@ public slots: void doAnotherThing(bool a = (1 < 3), bool b = (1 > 4)) { Q_UNUSED(a); Q_UNUSED(b); } -#if defined(Q_MOC_RUN) || (defined(Q_COMPILER_AUTO_TYPE) && !(defined(Q_CC_CLANG) && (__clang_major__ * 100) + __clang_minor__) < 304) +#if defined(Q_MOC_RUN) || (defined(Q_COMPILER_AUTO_TYPE) && !(defined(Q_CC_CLANG) && Q_CC_CLANG < 304)) // There is no Q_COMPILER_>> but if compiler support auto, it should also support >> void performSomething(QVector> e = QVector>(8 < 1), QHash> h = QHash>()) From 729541f7ca1129731a2ec79492d15e7ecb3cad80 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 4 Nov 2014 11:40:30 -0800 Subject: [PATCH 138/323] Store the GCC version number in Q_CC_GNU The sequence of (__GNUC__ * 100 + __GNUC_MINOR__) was used in quite a few places. Simplify it to make the code more readable. This follows the change done for Clang, which was quite necessary since Apple's version of Clang has different build numbers. Change-Id: I886271a5a5f21ae59485ecf8d140527723345a46 Reviewed-by: Oswald Buddenhagen --- src/corelib/global/qcompilerdetection.h | 24 ++++++++++++------------ src/corelib/global/qglobal.h | 2 +- src/corelib/tools/qsimd.cpp | 2 +- src/corelib/tools/qsimd_p.h | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index de8a53ea06..ef37f00189 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -137,7 +137,7 @@ # endif #elif defined(__GNUC__) -# define Q_CC_GNU +# define Q_CC_GNU (__GNUC__ * 100 + __GNUC_MINOR__) # define Q_C_CALLBACKS # if defined(__MINGW32__) # define Q_CC_MINGW @@ -187,7 +187,7 @@ # endif # else /* Plain GCC */ -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 +# if Q_CC_GNU >= 405 # define Q_ASSUME_IMPL(expr) if (expr){} else __builtin_unreachable() # define Q_UNREACHABLE_IMPL() __builtin_unreachable() # define Q_DECL_DEPRECATED_X(text) __attribute__ ((__deprecated__(text))) @@ -221,7 +221,7 @@ # define QT_NO_ARM_EABI # endif # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 && !defined(Q_CC_CLANG) +# if Q_CC_GNU >= 403 && !defined(Q_CC_CLANG) # define Q_ALLOC_SIZE(x) __attribute__((alloc_size(x))) # endif @@ -728,7 +728,7 @@ #if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) # define Q_COMPILER_RESTRICTED_VLA # define Q_COMPILER_THREADSAFE_STATICS -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 +# if Q_CC_GNU >= 403 // GCC supports binary literals in C, C++98 and C++11 modes # define Q_COMPILER_BINARY_LITERALS # endif @@ -739,13 +739,13 @@ # define Q_COMPILER_VARIADIC_MACROS # endif # if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 +# if Q_CC_GNU >= 403 /* C++11 features supported in GCC 4.3: */ # define Q_COMPILER_DECLTYPE # define Q_COMPILER_RVALUE_REFS # define Q_COMPILER_STATIC_ASSERT # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 404 +# if Q_CC_GNU >= 404 /* C++11 features supported in GCC 4.4: */ # define Q_COMPILER_AUTO_FUNCTION # define Q_COMPILER_AUTO_TYPE @@ -754,7 +754,7 @@ # define Q_COMPILER_UNICODE_STRINGS # define Q_COMPILER_VARIADIC_TEMPLATES # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 +# if Q_CC_GNU >= 405 /* C++11 features supported in GCC 4.5: */ # define Q_COMPILER_EXPLICIT_CONVERSIONS /* GCC 4.4 implements initializer_list but does not define typedefs required @@ -764,7 +764,7 @@ # define Q_COMPILER_RAW_STRINGS # define Q_COMPILER_CLASS_ENUM # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +# if Q_CC_GNU >= 406 /* Pre-4.6 compilers implement a non-final snapshot of N2346, hence default and delete * functions are supported only if they are public. Starting from 4.6, GCC handles * final version - the access modifier is not relevant. */ @@ -776,7 +776,7 @@ # define Q_COMPILER_UNRESTRICTED_UNIONS # define Q_COMPILER_RANGE_FOR # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 +# if Q_CC_GNU >= 407 /* GCC 4.4 implemented and std::atomic using its old intrinsics. * However, the implementation is incomplete for most platforms until GCC 4.7: * instead, std::atomic would use an external lock. Since we need an std::atomic @@ -792,20 +792,20 @@ # define Q_COMPILER_TEMPLATE_ALIAS # define Q_COMPILER_UDL # endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 +# if Q_CC_GNU >= 408 # define Q_COMPILER_ATTRIBUTES # define Q_COMPILER_ALIGNAS # define Q_COMPILER_ALIGNOF # define Q_COMPILER_INHERITING_CONSTRUCTORS # define Q_COMPILER_THREAD_LOCAL -# if (__GNUC__ * 100 + __GNUC_MINOR__) > 408 || __GNUC_PATCHLEVEL__ >= 1 +# if Q_CC_GNU > 408 || __GNUC_PATCHLEVEL__ >= 1 # define Q_COMPILER_REF_QUALIFIERS # endif # endif /* C++11 features are complete as of GCC 4.8.1 */ # endif # if __cplusplus > 201103L -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 +# if Q_CC_GNU >= 409 /* C++1y features in GCC 4.9 - deprecated, do not update this list */ //# define Q_COMPILER_BINARY_LITERALS // already supported since GCC 4.3 as an extension # define Q_COMPILER_LAMBDA_CAPTURES diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 8bc489e509..f17ff3dea0 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -877,7 +877,7 @@ public: // (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#382). // GCC 4.3 and 4.4 have support for decltype, but are affected by DR 382. # if defined(Q_COMPILER_DECLTYPE) && \ - (defined(Q_CC_CLANG) || defined(Q_CC_INTEL) || !defined(Q_CC_GNU) || (__GNUC__ * 100 + __GNUC_MINOR__) >= 405) + (defined(Q_CC_CLANG) || defined(Q_CC_INTEL) || !defined(Q_CC_GNU) || Q_CC_GNU >= 405) # define QT_FOREACH_DECLTYPE(x) typename QtPrivate::remove_reference::type # else # define QT_FOREACH_DECLTYPE(x) __typeof__((x)) diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 0b3bbc0ad0..5281723c5d 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -519,7 +519,7 @@ QBasicAtomicInt qt_cpu_features = Q_BASIC_ATOMIC_INITIALIZER(0); void qDetectCpuFeatures() { #if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) -# if (__GNUC__ * 100 + __GNUC_MINOR__) < 403 +# if Q_CC_GNU < 403 // GCC 4.2 (at least the one that comes with Apple's XCode, on Mac) is // known to be broken beyond repair in dealing with the inline assembly // above. It will generate bad code that could corrupt important registers diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 3241e09b08..891a3ff053 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -218,7 +218,7 @@ #endif // other x86 intrinsics -#if defined(Q_PROCESSOR_X86) && ((defined(Q_CC_GNU) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) \ +#if defined(Q_PROCESSOR_X86) && ((defined(Q_CC_GNU) && (Q_CC_GNU >= 404)) \ || (defined(Q_CC_CLANG) && (Q_CC_CLANG >= 208)) \ || defined(Q_CC_INTEL)) # define QT_COMPILER_SUPPORTS_X86INTRIN @@ -332,7 +332,7 @@ static __forceinline unsigned long _bit_scan_forward(uint val) _BitScanForward(&result, val); return result; } -# elif (defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && __GNUC__ * 100 + __GNUC_MINOR__ < 405)) \ +# elif (defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && Q_CC_GNU < 405)) \ && !defined(Q_CC_INTEL) // Clang is missing the intrinsic for _bit_scan_reverse // GCC only added it in version 4.5 From ffcad3244ff6e2429da1bf985d6d1116c251c2ec Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 4 Nov 2014 11:42:08 -0800 Subject: [PATCH 139/323] Define the Intel compiler and Microsoft C++ versions in the Q_CC_ macros This is for completeness, since we've done the same for Q_CC_GNU and Q_CC_CLANG. We won't really use the macros like this because both __INTEL_COMPILER and _MSC_VER are readily usable. Change-Id: I669c60166fa4839d43f84f339e6896321d62817f Reviewed-by: Oswald Buddenhagen --- src/corelib/global/qcompilerdetection.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index ef37f00189..4c84daae13 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -78,7 +78,7 @@ # define Q_NO_USING_KEYWORD #elif defined(_MSC_VER) -# define Q_CC_MSVC +# define Q_CC_MSVC (_MSC_VER) # define Q_CC_MSVC_NET # define Q_OUTOFLINE_TEMPLATE inline # if _MSC_VER < 1600 @@ -144,7 +144,7 @@ # endif # if defined(__INTEL_COMPILER) /* Intel C++ also masquerades as GCC */ -# define Q_CC_INTEL +# define Q_CC_INTEL (__INTEL_COMPILER) # define Q_ASSUME_IMPL(expr) __assume(expr) # define Q_UNREACHABLE_IMPL() __builtin_unreachable() # if __INTEL_COMPILER >= 1300 && !defined(__APPLE__) @@ -327,7 +327,7 @@ /* Using the `using' keyword avoids Intel C++ for Linux warnings */ # elif defined(__INTEL_COMPILER) -# define Q_CC_INTEL +# define Q_CC_INTEL (__INTEL_COMPILER) /* Uses CFront, make sure to read the manual how to tweak templates. */ # elif defined(__ghs) From cf30a3d9b2e8584fa419ea1a6ee3d64a140352a0 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 4 Nov 2014 11:57:55 +0100 Subject: [PATCH 140/323] Rcc: ensure enough space for the embedded The two-pass feature depends on the QRC_DATA signature that needs to be stored in the array later overwritten by the embedded data. Task-number: QTBUG-42359 Change-Id: Ida1ccff40dda28f92a4267f86f48ee96d62bd214 Reviewed-by: aavit --- src/tools/rcc/rcc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 9d8a7b7051..7623ce2e4a 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -889,6 +889,8 @@ bool RCCResourceLibrary::writeDataBlobs() if (m_format == C_Code) writeString("\n};\n\n"); else if (m_format == Pass1) { + if (offset < 8) + offset = 8; writeString("\nstatic const unsigned char qt_resource_data["); writeByteArray(QByteArray::number(offset)); writeString("] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' };\n\n"); From 82e266a83b8124df327001906d2848f625effbc6 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Fri, 31 Oct 2014 13:46:01 +0100 Subject: [PATCH 141/323] New Qt logo This patch replaces the old Qt logo with the new, flatter one. The PNGs were optimized via: optipng -o7 -strip "all" Task-number: QTBUG-41685 Change-Id: I51983a45144373bf7aee31a32990ecbb2582f488 Reviewed-by: Robert Loehning Reviewed-by: Friedemann Kleint Reviewed-by: Kai Koehne Reviewed-by: Lars Knoll --- doc/global/template/images/Qt-logo.png | Bin 4344 -> 2425 bytes doc/global/template/images/logo.png | Bin 2205 -> 2370 bytes .../template/images/sprites-combined.png | Bin 62534 -> 53964 bytes .../legacy/framebufferobject2/cubelogo.png | Bin 5920 -> 2884 bytes examples/opengl/legacy/pbuffers/cubelogo.png | Bin 5920 -> 2884 bytes examples/sql/doc/images/drilldown-example.png | Bin 52950 -> 9092 bytes examples/sql/drilldown/images/qt-creator.png | Bin 46906 -> 6655 bytes examples/sql/drilldown/images/qt-logo.png | Bin 45652 -> 5527 bytes examples/sql/drilldown/images/qt-project.png | Bin 37795 -> 16832 bytes examples/sql/drilldown/images/qt-quick.png | Bin 43238 -> 26635 bytes .../animatedtiles/images/kinetic.png | Bin 6776 -> 5055 bytes .../animation/easing/images/qt-logo.png | Bin 5149 -> 1495 bytes .../widgets/doc/images/dropsite-example.png | Bin 36033 -> 29056 bytes .../doc/images/icons_qt_extended_16x16.png | Bin 1184 -> 563 bytes .../doc/images/icons_qt_extended_17x17.png | Bin 1219 -> 605 bytes .../doc/images/icons_qt_extended_32x32.png | Bin 2185 -> 916 bytes .../doc/images/icons_qt_extended_33x33.png | Bin 2435 -> 975 bytes .../doc/images/icons_qt_extended_48x48.png | Bin 3805 -> 1270 bytes .../doc/images/icons_qt_extended_64x64.png | Bin 3805 -> 1614 bytes .../doc/images/icons_qt_extended_8x8.png | Bin 685 -> 340 bytes .../widgets/draganddrop/puzzle/example.jpg | Bin 42654 -> 42654 bytes .../widgets/graphicsview/boxes/qt-logo.jpg | Bin 40886 -> 20316 bytes .../widgets/graphicsview/boxes/qt-logo.png | Bin 13923 -> 12167 bytes examples/widgets/itemviews/puzzle/example.jpg | Bin 42654 -> 42654 bytes .../painting/basicdrawing/images/qt-logo.png | Bin 3696 -> 1831 bytes .../icons/images/qt_extended_16x16.png | Bin 834 -> 524 bytes .../icons/images/qt_extended_32x32.png | Bin 1892 -> 892 bytes .../icons/images/qt_extended_48x48.png | Bin 3672 -> 1294 bytes src/tools/qdoc/doc/images/qt-logo.png | Bin 5149 -> 1495 bytes src/tools/qlalr/doc/src/images/qt-logo.png | Bin 1422 -> 892 bytes src/widgets/dialogs/images/qtlogo-64.png | Bin 2991 -> 1676 bytes 31 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/global/template/images/Qt-logo.png b/doc/global/template/images/Qt-logo.png index 64c1c4aaa34d5dfcba8c12a7dcb3352140fec4c5..01256ab08dcf24aa990dc786723439f8dca192cc 100644 GIT binary patch delta 2414 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 diff --git a/doc/global/template/images/logo.png b/doc/global/template/images/logo.png index 1e7ed4cf21300f6695a894db7a6c2376dd65c288..698dde9215ca0c91d27745031000fdf83dc48ed0 100644 GIT binary patch delta 2359 zcmV-73CQ-H5yBFXB!6H~OjJbx004i#KzqVMiN{og#!r95M1R9Ve#1h3!a{w)L43eK zd%r+?zdwDyKYGAHd%{C}!$W(-MSQ_Ulg(wC&~T*Ge5}}rv)hxq-=E3lvefIr-R{rj z@!9S6=JomU|NsBHNSlrT000DZQchCF-FDLwrc6zCuYaO}j z<>lq{?CO(o&bhYfT=Ukrrhabp$r$Tg)3$BfG)>dErfuKe^s}NXYY%SQwoThKZQH&% z*R+j$Yo87M;(wfTSMJf8rrD$2IP0pXLBDLKd+r6@G>voHpJzZp z6Xi*`I-jp?9ko5YTHEL2+UfkRWv%xBr}H|CbsxENxqtmO=K1ml^WWym`F!uSn>U}& z=P6!-eQ>iPf2-=kMPI1<%iR9LoR|HdRM)O;+jcph&r^K~@97}XP%_ps1Hf9A+81Ch zD}dq&Kq&xF$_mV7`C9Ig3R7kDuz^>lt!vxrd_JEi?T-?;bCa(CCj7fMfFWA^Z}?#DF$B7eFZ8R$qN0bM6Vq3fuic#_~dBA1D1 zoD~ILzmQuU)2-IV7-RP5qSG+|m${6_HdpRIJunhu4J3h9blpUhODQW#r0l4aQZO@h z^D;Qf%lc(pJ_efB)>>=zHrUFQdp@5hUAyZ7G7}Z#5ZB4lOq3VuN<{;(0L9ZBdk zi+`sHP&5QTe--yoi80n%Yxm?`-*b(zt~t1CA4Avop{nZ3iPv0`;f}j1s)moWh4`;? z?fFvF_GI8=5qWUy`{?GVR)9z0JoOzH4E$P+rH^WRVFtjGRFy|n2_SvP6UHHPE`R*m zPk+E|F43*;x%#tY;J^Sn3b7|OdbRfB7-{H9@etKWY6ZHW2JhAA<2;fYy)R55raC4U z=ileH%QYFyyJV>A&ys;%0?>5>IE<)b1~3py;O&Jl0UhPz;b}roiK#~-27CF6p{Dn2 z*oWG9;ntr-w-dZl#fl`esy$1`cz^9GRwO{zmHoj)1tT#>0SCn@rmvaE%zvC2I3C=t zV-Xo*7!$D&055i>p&GyL?#qjvt*P&+olL21*-^vMI^7s(=1Z9 z<h-k%C2JK@o|RMHZkOee%}*0rztLD8^i-F|Lg7##nb;`G1kfDBhPbC>67K zrO1yZ5C&3;(%=~r^}wu1MILCtL_Crrnj}<2fo4>s{D2%{2Gd9s6!jRrB0ou}h}riP z%LA^vs3zu}o{cfasP)R#w_MLyiE@l3he|?RCB_nIB3eoaDR_)F14A5FPbnyjb|hMI z=q0LYRv|AGGbs!{CVwbD5tTwTkuN#+5-CfdHQDrl+nRiTV7e-;jWK$>;p+F%MMn~% zBqHe;#ZxAdPyrn!qPe0O=sK22nP~2V1d9RG5ZX(Oe>-M3QSCp$Y&d znI9bXYjtygUVnP6?N-T*(OTEFuJ5>YB`Ty={5sp$9UBu;!W+O7JM2rfZ*>;#hJ~G<@VXR_k7tV@s)zO{TTh)_RBA+vrm8 zX~kUm;8}c#p4SpQvIQDNK0%cC+&#{9eZ$4g6_pth`|EjrDZpA}4+@r2ZaXhWr~b1uzWMg6 z7Odsrb+yJ>dz1?{TY3A~+`~14c)qVuq<*>{P#T{9eBcU)YXhhDvl@0I)TtCn(S zTTA)%d4KNzzq<0_B5TteTi`8!A8{*u|BCEpJ}Vcld6*0@&%}MT)%t7h>8ZGl=Dl3V zlLhx7_tj}Tj5$l{wRtM-V{T)u(Rx39{-8ZQ8+R)g+XbulQ^LzP--r5```S2bwstH1 z{u}i^;l4J`J{R=Y+}FlAS3TWLrk`-DC%uLD12DIG>Kml5+@|^ocXGeIy}nj2FF)i) d`O{B<;vbxPMN7MTCAI(n002ovPDHLkV1nI(re6R6 literal 2205 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 literal 62534 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 e!T^AFemsJ~Dw=tA8zX+*eA(eV_KN4lli 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 gcDBye*Fc!YybcN diff --git a/examples/sql/drilldown/images/qt-creator.png b/examples/sql/drilldown/images/qt-creator.png index fa0f6ed7cef5f69db1c781fe79eb05a992902607..0602bdcad1d643ad4b4b43600b28df5ec681543f 100644 GIT binary patch literal 6655 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 Csx$lm diff --git a/examples/sql/drilldown/images/qt-logo.png b/examples/sql/drilldown/images/qt-logo.png index 53bc39c38c11e10d7dbb567a2dcc59da7fbb2f36..7603fa0c903907396e2220d9a8b04788c9d202a0 100644 GIT binary patch literal 5527 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 QYXATM07*qoM6N<$f}T+zM*si- diff --git a/examples/sql/drilldown/images/qt-project.png b/examples/sql/drilldown/images/qt-project.png index c34d3f099dd2a2f95e1dbfd7a33fc98c8b183f44..e066fbe3f98480c65f646dc28d9897e07f8f2c24 100644 GIT binary patch literal 16832 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 a@c#mr<$02Fk=6SE0000P)&00001b5ch_0Itp) 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 VN%T@j?!N#4002ovPDHLkV1naHwAlav literal 6776 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 Ll#2rm;d|?EtfwxK literal 5149 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 diff --git a/examples/widgets/doc/images/dropsite-example.png b/examples/widgets/doc/images/dropsite-example.png index 2c42c7be69ba33fc1a4c9a3488d6a326bde109e5..c555dd3609ec974543ee85d70db8ea4986affa8a 100644 GIT binary patch literal 29056 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Μ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

{MuDgC|t8YIW(lVduA4p0w=` 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Π0`9idl})Ofq+iyh+r%FDjR~ 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 literal 36033 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 diff --git a/examples/widgets/doc/images/icons_qt_extended_16x16.png b/examples/widgets/doc/images/icons_qt_extended_16x16.png index 92743690e30d05fc47da7663b3db16c61d8a6196..8bae9499e4523137225eab0e9f125536f58ce95d 100644 GIT binary patch delta 549 zcmZ3$xtV2xWIZzj14G)Z;;BIDZGcaRE0C@`O>Z;sx4d;I?UOZPuqc<|xkqmNe} zf4cVM(~aj}ZomBc;MLcMZ@)fy_x;(s@6X@=c=7T3t4}}QeE#|N%dhuee|`M+`_qp< zUw{7j_UrGDKmUIJ{rl(dzrX+f|NH;{ze0UhgBt?_BcrE_V@SoVx7SYkIR)}GByz<~ zh)i*Fa}*SvdXv+IW$MFkf92Z`bWOdT^y&ZXy!}s9-hQm;Q!?de;Sf-8XkcJu!om0x zYCnBPhRxo!zJi%IpR1fUk2P+QN$Dt%d$xFu$JO-C74=zbxAM$i^JiK|<1s(e|7+Gy z>v(xg+df>AH&RLLzLI>urfF^8!q=1UPcwWJx7cy5ifKZp#*XV>JzZ|;_dVUDrMLgw zn(0$dJk{AJZ5ZtGq1Jp)`L^wc=dZl;&F<~G7nLh-O75=7!s9|YkldsB3VjQ7+gJSX UV?1k}4@?0Jp00i_>zopr0Ch+z+5i9m literal 1184 zcmeAS@N?(olHy`uVBq!ia0vp^Eg;On1SIdNiF{ySU`h9MaSW-L^Y)H!hD@olyWxD{H}AgCobgLci`Q@N;RALhvnM-KWx;u z-hC#~g`-VP$!q0;^a&ZWma*?`{C7mcL4uhhnIVx!p@*@>u)%;$;26W9ffJnIae?{O z=U%)^Qlu?Zc1N^cx_yk-aWHRs?c}K0&_FHl>C}~iT?L%nRkU> zTottM(Vt~gA~w3*>3BUW?ReDnn{#j9et++#rNEanZY}S7&+k$TjsJW^_snVMyXSfD z{hB11sTCGx;~%Z3KX;#ra=x;b)LHOX6oJOd%HF-zaN`%yZm_d^Sa1; ziME^VEMpMSq&ss8-)?6%wO6n`^bcj?N@T)WpWt1DP@+qNU!s>i#e z+WF*VEO-9@^Qm>}l^;vjZ(h83@nm)Nu64#HCL&*+ShWD%rm?idR!ParrSsF&_n~)R zzI-2F_vdVgRjl>q*AruvHbrQ#SZ=9%*e%%YR#!gl$mAJo{_4Ts?ceimOTD?Z3utW6DWlovrljlZiJ8Y#U>mUV`IG+$Wblgtl1#i2l6C@Ib3d38!Kvor#}zHg($BwCU&4W}M5Mc|LR2`RrNebLL+v zUVNo;@s+A&*XmYWYgl=$an<#vH8)z;+-O~Uqiy}o&J8!a>o?x&*>tOK^X&;+Z%^8G zXUev_Q?}ooy666!y$|N@yT4%Hg9Qg3EYKYRbfg~y++KK*>-#g}_8 zKi_-#_1>FrkKcZM^6vYyk3U|0{`u~E{qHY7{(SxU=i9HpKmPpt{qO(3|NsAAysbP3 z7#?DtE{-7;x87b04`K=wa7(On6*$JwwP?Wt6;Z?IJuF8%_`dwx{%A4xhEwy}i_I>? zhlYRMyD>t==(|G$Ffds-1Qf6{lvZ{0zg>Fi-`mqCMC&h3QOQ)=y{+8zgVUMU+YfLH zdh9%17CCF)Cl{5rhjXu9Sy`pD?M=kouFo#^s|f`!SfTXpi+y|&m` zDtlv-{-QkVT|Z`hbzO5~=Pv)u+rAb`kJdkq+p(%{$IHq!P1UQtW?kt~b~^d6*lkkR zJdUT)nVu{6X)EoEu=L2<-+y=Br$@&g9=<*Q*yp{>_#Do}((&KLWr6(E%lo^nd=w3U PX@$Yl)z4*}Q$iB}-v>x~ literal 1219 zcmeAS@N?(olHy`uVBq!ia0vp^Eg;On1SIdNiF{ySVCnL7aSW-L^Y)H!hD@og1%WC_fvE@zY`P_WoJ#~vNes*!ODYQLrTzcff zvV}h0?nb?Dt1tQQx%AyH*hKitrCqJ>JJ0WX-qmp}C`Ld1%fEE%ct4k*r&%Wpy|ZU) zZ`QuP?o9pjkn2tJb~-C|D=u<5=~cLQ`L|o`&dYy4cE4Bs%*XC-@#9sce?Ib`TDN$L z*wQAsoz4rp726j6pA&w3p1o!GuBummZilanwZHM@nfLF$_h)5aoR<0UC+Y%oxn7Oo zmT7F}S2tKRk#MW5 znS$4gd6#xeAI;IKOwKFXc*DBr=kG1={y6^KqFq*8Q?n-|N?(LaR#w)L|KIvUjZKyEom7Y8RL%x$oA5 zr&oKEw5Ann&7PU_dGDu1Kirna%-kP*_smzvsI^shf#E+1U%cz&((kE9*z=AW3R z|HrE4%~56lWBxLAzgj2$-0Usw{W4>>>}r$epVO8+{5R1swlx17%kFJ@54#`!u8Yq8 zbmxv_c1Uf_mn%PK>g)T~N9P)!|7Uc2@x6>*sjwqE>X%4g?0d}yRKIXf+K+j8Z$sk$ z|9N@j%aeU~9B+FaeLPV${amqjC)?aVzf;|}NUxGmv^KW6f4eI9vh41!;==O0Yrc1X z%3ZCQtR8aI-(}0y4W(&QbVAn}9dq8ie5?2Btt&*kBR#Dr<@kz3y;=91%iXv)*VwoC zu(+P}>Fs~rqFr46T$&rbE}FNZ(AG)p@#b>-nI-4mp6C0vY`)jgS^xjuzg2W4a_8G~3JontSEYmt)TbJf)e%@0HbL}rh>FeL$UGZ^}*_O;1!ISrQPU`FX^MB6= z$Cgh_`_{gD_io*~yM4i$YpqwW&X)FD8dTWc#>c*QHJ{?{`5!sB@Bi&_mmVzH4V2jx cZk>zIEYl3x{v}{9uyA7VboFyt=akR{0EML?X8-^I diff --git a/examples/widgets/doc/images/icons_qt_extended_32x32.png b/examples/widgets/doc/images/icons_qt_extended_32x32.png index cd3d0f325510c53d0e1a76bb1ac8249b781bfa7c..7b0c54bac3ae1c2b4e5edb0cd9be6557b3303ea6 100644 GIT binary patch literal 916 zcmeAS@N?(olHy`uVBq!ia0vp^Eg;On3?$QL6;EYgU~CKU32_B->kc{9A9Aiglaq8LRIT!NgUd&&3xpdLx@+Ft6mt3h@dZl*h z)!JoO>Xu(^SaGdk<+a9D*PB*fZ(e=9WepJB0HW5lH`>XCJ@;qty+42NgSq?eFWC2B-u{OR4?J9a;Nj9kkAP^|iKpvNKHG5m z+2%9Pww-yt_3ZO)=U(hM|6=Eb7rQUM1fo5cUhcc}YVYM&`!2uQf93UotFI5OSFT=l;pi81lSpjAMI4#rT4T9+`}-?rr`szF%7=STn)3RFsmaGAJ+?v*?#(&Q z=Q}s1Z|?4mSiV0v{+8W_6&!z+y+tS5*SQd+@^D3o>^2eWQ;r?V4$H4_hnF$W&v#dFYuI`z&109)gG`nrp-XO=yh~=*oiKG* zkaJR6so47TFU#G|nfB@nSj^fK;|@!E{^EL@*rEADQPclP;T@)~OH~TuZ4zu|o^uTr z8yqoP;QgxAyRc)K5s&xu#O2=(uWFmX{zm7ImHnh5`^8f=^W$3;HkC7a+*0YCR3F|gCz3A55Rc+@OoN6w2W!vVZkN#}>spQyk zil?mTk8EJauSYk_e3MkUEjS YQrzdN^?@bz!0g4~>FVdQ&MBb@03_r5v;Y7A literal 2185 zcmd6p`#;l-0>{5AC7Me&ms}z%_ouPB_ArU0HG5*x+(r?FT*p{53N?;?y$eGlAevqag{P``;&*bdqYpqkAx+l*8XVL(nrAsBlPtpEtYFV-m z-DJ;um6Qmuz2$Cg_1lVBr}i+kQm!ce=YOmR+~+`z3m#rL!S-0;SZr6F=itXss#5*; zG(*ywHjYH8Jt{0y`hGq?#e2>qT(_!+64oz9P5&AiMfNCN4>g!a&(an2WI8ZZ*>)By zqwaLKs+r_0enrF9_|jefa0P9t5fwAmqH{4NoE)?nJOR%vAr&4Cai7}kv~zpXUTMp7 zRSuPq*@O}q?Yo+fO&|P=VQ3{Ey7lc`5t51h5)%uSKUn0HKj~rXXs2>f{B@b~yk8f1 zyQ`SY5i<{FlQQm>^_n@hhFJpYKn~>nnB$TkI()hbx3_@!j1i?n8S!PAgR~*q-k+XW zU7nyn(ghsrdXiSr@*_4grXX$MNGUB&qrB2+V~yEr{CaefRq zZf&o?Y?Q?oi1p!;27ESzvAN5kvbGE|ZxVntZ4eNNt|zGD_i@ixy4;Ns^*1H0(;&i! z#qv9b&(<|vUe|~3fIeJA*AR^v2Etz2tpqU5%R1iL*Gs&C&4nhF<>oIXwg-y;TvzZV z&2y9{qmO`3c(2Y`fE-STW$0vk6$bLJf`ZE691|%mmL=C_*=|PpTgZo}zA)Y5d9?tO zw{iZ8b`-M(wbdRz)J96!-AUahNRIm$GqKp4I}|RyMGLd+E)NG^fAD~8`OujskHO+Y zT+knGx;qZ$rAAM9;01A93bRGn#(S*udHwU(dgMh!cRiEe5glZtlyRnduac48z*f6{ z%{mx}_!`5O*^T^`4dzQ}A@g+jgCqNZQ$699`_P$>frrjNi9v6!@|(T$qTaCvE;ozC z8_kzOuh*8V%oBI3GulqzYR}~W+5n?v^Z^)9Eq03Q2vAMBs?4uNW{Vc$lG@jQew|u7 z((}5}=S7w}MGg$99tjQ!dDghFE8fE5jBT1?`i{}|82dJVP!mXdug@v~ZK(GzRy0j= zyF*kSYuFyEGrKIARdA)tXM-$lbErkp zie+kACGe2dDpfN@y(+Rr#(h{JaC2hb+(w$AN8G9T8fqeIe9bYZwV2U`5$h9oL{Zh zPgJ(Z-h7AoBWU`9MFS#!ZuUVmVBf9!yq4A_p{G*WK84e&lC=?>whnnzLxybzW-Y8G zz}@pxH>We4+`4?J{=;2}TFriF80tdF=S~mX^?<~ox;J5x{uw^4o&@SGTMV1*ck0jF zgn8kl6lLGuFRWw^d)wn>!UR>!`@LKpx2yy(sK!YoCh9~^du7|K1|+<_nA*85Ibkmp zxly~DemUKM{a8K?LqwR{{-hPWKnSkRo_~4l8W(%8C_p6!p^R;i^iSL- z@mKmc_M#?WGk5?&3JRp3yOxJed$9uRb5s5`ZWHqwE{9UO!EIGWDeYcTrM+r<80y*i zqGNpF$W76Z2)Mo@lbrB%9bh#5`J5t#*6vQG*IuL2foGwpZ=a_hYM1 zdrlO`y`QR}w!;#iTr%v4QtO9eu)*J25iRb4{)$tuyL1&5RSvST**3o!*%dgIHo~6O zB=(N93gKPWPdx4s4C*q}(iL7tVNd6#B$TS84-n}CLpScfv-;lmW6i$e^#S=Uwc0J6 zLsJoy+A0i{a|kCPpCm18xpq+&t8*V8=eC#Fj>7j(I_cvk_GhkS%aP*=B3D1Hxu<&E z{eI h7|fI_&{*SNpc(&OYtv{r_V>jAoE=>p8twgV{R6ld237z7 diff --git a/examples/widgets/doc/images/icons_qt_extended_33x33.png b/examples/widgets/doc/images/icons_qt_extended_33x33.png index a67565cc2bfe6ececef0fb3df89ad485b3f6b661..1a38f6e44b0653dd3f2f7403f5b39d74010df2c4 100644 GIT binary patch delta 964 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 diff --git a/examples/widgets/doc/images/icons_qt_extended_48x48.png b/examples/widgets/doc/images/icons_qt_extended_48x48.png index 5aa2d73f71a3ef6427ec2c3177beca338af62159..85dcb5f26c6ac71c5e01c01a0b50c5b188b5769c 100644 GIT binary patch literal 1270 zcmaLXXHe5;9Ki8^$O%EktLH$A1GE&-E2EwsyPzg!Cd zfD`%z>NGTSRu2LWHTI9hasaT~iV4OZgPs}vM>G48S^cOiGUV8O@=rL*aUA7DHU*tC z5cFUmIF}ldM?HzBV(>IfK0T~}7FGb2jxD5}DWr!N(a$^_JVzKjPhdnmVq7R@{9N+! zQYrItDKoN+b)}qjwSpB>!HRvtzW#(A_jD-k8Rupd=T_Bl{PW@4)x!xjBS|%*$+aUX zwWGfgM^lKSsdZy_>&AX>7|&>!$oz96t8o(ddNTVBH>Zi4+sw^t=HdV1<+t*RTBnNM zP7&Is9<_af6qBY(Nc>_FzoeaC+RlIcj$igpP}adO?+`#LItAsO!pbf|WtZ@2x9~}i zsOtTy=YNZ8dL?yzk{A7}UXo`TC^N4Hq_3&cCaSE7CT*fYl{F8_S{br7hP;&_fBR9< z#+1KfDo9L4J4@NYR(1}p>KamYag;qARriSc!>Ib7i8=D*9ECei<;~Nk=INgn82kmM zK*JI)3<))Cp=L;=<%l)IV(o}nJ36f$lYAbN=q6@#<5JzERL7M;79l+Os!s|%U#S-; z^+FZIAW|E|YQyxbetH(FQ8I6oE|}yCCWXeN`fQoiS?2T>jebdESkf9noe5ktfqFA& zFfSV{pwR-FEXzjAGF0=D)eKsfmTjQbx@@&UthN=~%F4>%N|+7WkY{Mr5p3$zJWp|Q z^QmnEQS1UwV?n_OVitFuv6;JN9e2O68NqFdI{qtyh{qFgbj^=?@?12w2%qZXr?Kee zb6+oBO}Lh_5RApXMhLGUklXsd$o0)}TOak`>x#QXMF?>@$p@92KHrLRL7(=_kaX8| zh`=LEPKxS425Z_Se&=3xV=Lw1#bj~Bivy^}jOUjIFAjbC%CecQ40C zWsR0renH??0V@kE?Y3j)yZXyFlsIBGGY!4D+%jxdx`%TQatGWKA>S8y*31cYj`i-9 zMP@iw8Si`A`R`^9^t$iHdjLF9Ku4OZ4(4s2=v6!mzhf_s^{oUWHaWo7W?SGbB8NS2 z@!b~3Mu$USKs_w2prU>kkeKdj5BEJ+N`>i7_c4yW!RSDbWgk0EpI7t+>Eu2va20)e zjW6*g4vDe@9@oDJ5VX*pE{AOK*7&snooRX6cDJVMX50Z(Pmfc0RF62~A_kqzPHO-O zhj~X%Rc?2A6-^Yx!}H`o@Zx*thYtSw$F)siIlJt}(HAoV)+ZI77o#tpF}}=YUTOt@s2S}JB!y1e}C7~cY~E)zhuJS$`3Lgn&HI+xpfzv zCn*>=Y=>FMq+LJ6n;x7cVQoA7uHCz|{Tr8ii~qMOAxIJ~ZH+MWWeQgn;0}FY0Qy)c Js`+Rn?q3c_)=mHb literal 3805 zcmcgv`9IT-AAiTpkz=Gna+Nblju>()#~dw-a+XjcL&z~3M#z=>9%|04+#yDCe{6E( znxjnnM9Y@kvTxt-AMt%Y9?#eF@%-WWcszf6JrnJ0uJiGT@c;n8XJKv%|Et*ll8f!{ zU6d1M0093h3sWQer$zMQh$o1t{BENE#%9+W>f(7Vf3|3b9i*sS75?b>DaD&E{Kr4G zsC(pw*y)m#D_zvjHa}^;=TJxg{pCTkN3%<@CjREhNOrg(^673&Ip&m*xiQy?#}Ydz z(pB1zt7yv8veoJgO3EWvMt1flJ;;AspZKGL*ttRC#+Zsg0BzbTAsz&Ik=4PUv0^UD zChf_E&60+|;|>4+#eyrwkc(whGR;>-O~-=Aaj=cZgBfZ~zJp8T>SWGPyQNO%#!sF0woY_w z8Hl$}EF`hCCcQqWYvbW$X;sN={o4cuc0pL|`^^E5!p{{)D;ESV9vps!OXhJL_s`pJ zrY~H&y8Z1cRLiqk+L#O2_%RIg5%K->ki^;MgHWSUS9p@vjw=SSK5>KEBXZK^@NH_7<8mb3GR(XTj1&f;M1$H}rM5 z56gNQ9sK1r6u(P2=hU^^ZB1O*HDVf8(~E}av=LUx$%-7yK3V@;;+MXLqo~Fg?D)8 zTuIDLl?%=ZTCT!YU>S(<;-SgXL`BvI10tc?MJY<&wGaW# z(gMVnVfYwR{4@`U3rVOJ)-Ydf#E*Z@nK`O+;vDaNB*8hMi~H$VAGp!U@y)J0HH2MX zjBQB4M&3D%9TA%ocJIALtO;n@S2a^9TZj+ijmB}4ZoH~W7#=(TO~ z>*(l+7)U*9Vq!w;(3Aw%gOLF8IBz6r_B(lbS(pd^GF^fLb3!gY0mH?GDU@6z$-Be+ zv?7H7slriyUS4r%;H%cw*3Qn(#>P#?mtJ;u_Sm8ORzaKUWIc7bwT?G7v&;viP;&4! zV`bG=bZLwF!u0wuZydVyp4IeRZJMl55j$eaPRbp0(Xy&SL4T(%3Hj&U=bt1J-YS>i z-1h6Rd8Jn>J^9|+O9iffT8oVbd4yMZXK++A(91IO?}N-nq>z*3x(`*|-*vmqSbsp< zqv+YWGUJ|L9s;e=SI)M&01wkl-mmu?>QX@0+wopXJ&?m6Zn?w|B-+z@)FpK3qNn(?ATAC~#;?xUL<{S>zEXUg zrjP2kV=*)}JHzy3Y|u(ds~{JpB>2EDAUd6Wy)O2N_>gMN=Qb43bn zC2y=Pd_CYWv|PgZKKngv(uryry*N>BW>V>P!pLx$qRI=1{ILDE{fe5Oj>E@{9;h%+ z zR~9>&2Cb;@{U7&`HwQ8~g*GM;*UN;Wm>+KTR?4`B?y*g1@Gck{+q6MnKny_x@ysd@in2a_=0tCgUrNIt1U_CfWDz`OA6rjz2^nJ`HeA96P_`9!T9{lPox%XhecDgH z#nd+tAFABCg23)MBZfv>VSDtO0`j?%2cP_QnkT1nEM1mnpD>1&-v2?RwdIH@3zxR& zyrW(V_FHOgeZPyT{vM{akbAY_p_t5E7{iYd34pr61sbWp+?Ou4a4Jn{O%9$ zo)OUq6LT|pn;0q}wVJ;3+sRSPUfq?j1zw1+z6MpX`G)=RP0o^^DPkW@* z<+NIDG$f+79q<|Xd=752foF}f16;*$P!kfjnVGDTSsZ)0WjZnrKp5VzD|0+75h?{K z8o`}eGI>Lun$~9LUr|sd_M!mL4W$P8ert+9tWQnx=OgPq>2nU)s*xn2Z#%%ILv8mA zUzL`}fL;KyRq#oT$>8z}rqhYnZpfN*Lt+w2t3HltfV6upng2>P@d8K}i8ojJN!9xw zLRquAT}XbW9ebem0*8G}siN3awXxB}n5wFKdTFBcbC7kD@;#BNYI8*)kTJLH8mFUz z#AVam9_S3elQvP7G8eV_tIgIQP4F(&brPAIZ|z-?kgg;c(Dd>xg1&y&$peFxg?Q85 zG4X8YMM`@BZbwrsyBo)%&&eRTv;LS_{^PqwR#189tRCu%ZlFycY&fE{4Y{}SYHwtI ztzL3mEfT26EMmi#Ldun3(&pS!04GCK)iADX-6&u~6K{{DmwM&|q&gLfu`%j}kBW~OHIZ9LCqe|lhs zy$oKpc^qf%mwTy;_F2@xHIiA36YHqL|0+*=zy`oBFlNrBwWRnTzg>nqIp9%pB<^(YxP>$0Dk@GHI(CEq^bExh-1_#M4vKId?&y#Je=aaF~m zin|3l2*H$=R*-%83vtrkcLu sjZRks84p9a6iuZ5-zMGMrjNz`eLV9O6MK~LceVl+W;Uh-WA~W<0H(DikpKVy diff --git a/examples/widgets/doc/images/icons_qt_extended_64x64.png b/examples/widgets/doc/images/icons_qt_extended_64x64.png index 5aa2d73f71a3ef6427ec2c3177beca338af62159..d0bfd97f10b47284d9ecb6999ccad8079220b274 100644 GIT binary patch literal 1614 zcmYk-d05g17zc1>hgTNbQ}S4QJeFG&YuVf?-Qj^#XLDIbT4tp^mR+V+wtU>YLsV8? zQ&aOu$F$_|C^b5OffyB^Jrn2!u76TI{-SvPML{NZdnI-MlGN>;O!Y~j`le8S zO$GIU{L*^Pr1kuk-V5@7*84lU_bj>(6p+z(4%2rY(;t}Ge<7@2EthdUj}ex~49{nV7ce3Um=XUB-YjHB77j)hu|T(rS$AKu@0GCc zmkdRfvZG4D9C}bT6kRqH^NJH&&UskDiL2l~s^C7ZsBq4B&7JRd{gWfBA!B0q~L0A-W-Sdsus8pAdS{%#lpJ#Q3(UNi}F znuNK{!o243ym#XTEuz8}QBkX?s7+MTHu17;qNIKD6?vk(W2&Nas;YCUx>H=$HC59k ze%&Rmrig1OVjM+M(=Gn5Tkq-ct9Ua2h(8MmW`QxOS~v%cW8AkD;rW^zF@wFp`fFRe(HR;Fc| zX_7Vt z3E8BZ=3a2WB16XR;rn`Mp=h`54$veM zq@9uFC*$Vl;#v4OIrh~JuMn8etw%7c_8ErvA5e3&`{_Lx!2^}WaWT{h%RR+4-{mx>^dTKz!7nzQH5s*~ z;FeqsyCQ%fAEe8HAJpd?M>*M*A-+<6qRGi-&*3M)byu0E4i&H)T}W4jK6VZ0)w+;1 zlMu@t2yarJJ06q%#-BCQ7P!aS5kd)le|3(pY(3+s&+dT3E01R8o9#E|J~V<&vBY27 zyKn-xXTf^JUQXQ0xFc4lO0nj^VCZLV)CUw>H=LQx1xj$zhAWDQ+Y8*WxpLhy5+S#a zwa@;EfDT90VDvWG?gTU)ao;(lt+(4j6(qEu^>fCidzr-FYAsZ-PZ{keX7nJOey%3k zB0R=!mFnE84j{r%Rr?x>f3ZM>Au`{k;mTjuhJKa_8?1bv>B3c)bUHXUA>wX2C8j%H z+kTpvadg{NAkxH|Wn-KQEpr(mJWNdY7YBcv2rUgJN70R+#WhODV#sZmwRR(x;ueX^ z0je_L#68Jk9I5VEN2ERU#a-oT>PYnNcKi|4vSeI*(j9u}JS-nYWI~3dV_s_NZZ$yP8nBm(fUE|$?@TLHyDyimBU!<<4CLYXXUFJAnuYUBZ^Y1# oBsJK5P@f$7CnGA6ki5EMN5lnn!hOe!;A4RJdif*kJ+3AH4;Ag7ssI20 literal 3805 zcmcgv`9IT-AAiTpkz=Gna+Nblju>()#~dw-a+XjcL&z~3M#z=>9%|04+#yDCe{6E( znxjnnM9Y@kvTxt-AMt%Y9?#eF@%-WWcszf6JrnJ0uJiGT@c;n8XJKv%|Et*ll8f!{ zU6d1M0093h3sWQer$zMQh$o1t{BENE#%9+W>f(7Vf3|3b9i*sS75?b>DaD&E{Kr4G zsC(pw*y)m#D_zvjHa}^;=TJxg{pCTkN3%<@CjREhNOrg(^673&Ip&m*xiQy?#}Ydz z(pB1zt7yv8veoJgO3EWvMt1flJ;;AspZKGL*ttRC#+Zsg0BzbTAsz&Ik=4PUv0^UD zChf_E&60+|;|>4+#eyrwkc(whGR;>-O~-=Aaj=cZgBfZ~zJp8T>SWGPyQNO%#!sF0woY_w z8Hl$}EF`hCCcQqWYvbW$X;sN={o4cuc0pL|`^^E5!p{{)D;ESV9vps!OXhJL_s`pJ zrY~H&y8Z1cRLiqk+L#O2_%RIg5%K->ki^;MgHWSUS9p@vjw=SSK5>KEBXZK^@NH_7<8mb3GR(XTj1&f;M1$H}rM5 z56gNQ9sK1r6u(P2=hU^^ZB1O*HDVf8(~E}av=LUx$%-7yK3V@;;+MXLqo~Fg?D)8 zTuIDLl?%=ZTCT!YU>S(<;-SgXL`BvI10tc?MJY<&wGaW# z(gMVnVfYwR{4@`U3rVOJ)-Ydf#E*Z@nK`O+;vDaNB*8hMi~H$VAGp!U@y)J0HH2MX zjBQB4M&3D%9TA%ocJIALtO;n@S2a^9TZj+ijmB}4ZoH~W7#=(TO~ z>*(l+7)U*9Vq!w;(3Aw%gOLF8IBz6r_B(lbS(pd^GF^fLb3!gY0mH?GDU@6z$-Be+ zv?7H7slriyUS4r%;H%cw*3Qn(#>P#?mtJ;u_Sm8ORzaKUWIc7bwT?G7v&;viP;&4! zV`bG=bZLwF!u0wuZydVyp4IeRZJMl55j$eaPRbp0(Xy&SL4T(%3Hj&U=bt1J-YS>i z-1h6Rd8Jn>J^9|+O9iffT8oVbd4yMZXK++A(91IO?}N-nq>z*3x(`*|-*vmqSbsp< zqv+YWGUJ|L9s;e=SI)M&01wkl-mmu?>QX@0+wopXJ&?m6Zn?w|B-+z@)FpK3qNn(?ATAC~#;?xUL<{S>zEXUg zrjP2kV=*)}JHzy3Y|u(ds~{JpB>2EDAUd6Wy)O2N_>gMN=Qb43bn zC2y=Pd_CYWv|PgZKKngv(uryry*N>BW>V>P!pLx$qRI=1{ILDE{fe5Oj>E@{9;h%+ z zR~9>&2Cb;@{U7&`HwQ8~g*GM;*UN;Wm>+KTR?4`B?y*g1@Gck{+q6MnKny_x@ysd@in2a_=0tCgUrNIt1U_CfWDz`OA6rjz2^nJ`HeA96P_`9!T9{lPox%XhecDgH z#nd+tAFABCg23)MBZfv>VSDtO0`j?%2cP_QnkT1nEM1mnpD>1&-v2?RwdIH@3zxR& zyrW(V_FHOgeZPyT{vM{akbAY_p_t5E7{iYd34pr61sbWp+?Ou4a4Jn{O%9$ zo)OUq6LT|pn;0q}wVJ;3+sRSPUfq?j1zw1+z6MpX`G)=RP0o^^DPkW@* z<+NIDG$f+79q<|Xd=752foF}f16;*$P!kfjnVGDTSsZ)0WjZnrKp5VzD|0+75h?{K z8o`}eGI>Lun$~9LUr|sd_M!mL4W$P8ert+9tWQnx=OgPq>2nU)s*xn2Z#%%ILv8mA zUzL`}fL;KyRq#oT$>8z}rqhYnZpfN*Lt+w2t3HltfV6upng2>P@d8K}i8ojJN!9xw zLRquAT}XbW9ebem0*8G}siN3awXxB}n5wFKdTFBcbC7kD@;#BNYI8*)kTJLH8mFUz z#AVam9_S3elQvP7G8eV_tIgIQP4F(&brPAIZ|z-?kgg;c(Dd>xg1&y&$peFxg?Q85 zG4X8YMM`@BZbwrsyBo)%&&eRTv;LS_{^PqwR#189tRCu%ZlFycY&fE{4Y{}SYHwtI ztzL3mEfT26EMmi#Ldun3(&pS!04GCK)iADX-6&u~6K{{DmwM&|q&gLfu`%j}kBW~OHIZ9LCqe|lhs zy$oKpc^qf%mwTy;_F2@xHIiA36YHqL|0+*=zy`oBFlNrBwWRnTzg>nqIp9%pB<^(YxP>$0Dk@GHI(CEq^bExh-1_#M4vKId?&y#Je=aaF~m zin|3l2*H$=R*-%83vtrkcLu sjZRks84p9a6iuZ5-zMGMrjNz`eLV9O6MK~LceVl+W;Uh-WA~W<0H(DikpKVy diff --git a/examples/widgets/doc/images/icons_qt_extended_8x8.png b/examples/widgets/doc/images/icons_qt_extended_8x8.png index 8de7fce038a3df61b43bc204fb774680cc31271f..dcbb5811c6b6548de08f4d561e80167fadb65812 100644 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^Eg;On3?$QL6;B0HMFBn`u0Xo(kW>93=f=Zs9mfMZ zj|X+12<ZQr*0nd zlI8|v@Wc8@(ViP~-zB=-j1S*y)Vm`5c-jQFJyyQ4O9lJiJ(aq@ai{P0!zPPtd`?A5 t7|wcs{(QN_$8H5Qa0%5G76IKC+{e1xc~9*2*$8wfgQu&X%Q~loCIFSUqMrZ& literal 685 zcmeAS@N?(olHy`uVBq!ia0vp^Eg;On1SIdNiF{ySU@Gx+aSW-L^Y-q3zu-if_K)Ac z90*L-Xmd=CQV9|26uL0==!+*QbLN<+@$IN!zSlCjb9Fa&Z~1|Qf(vc0f(i>W8F;yt zss8J1_-e7sLbm<8<=M|WoAN(B`MxfnTaN@F>rIU*V>YZzHVYR?l18YbquDxp=u)a{n)V)qOqp{(Y-k zUsd|)T-y5Eul7}Zdl$I>{`(TEjpd@@k0jcgn@>+RpTDnehechv;@)qGf4w)~%+WJX zey_Fe$oY_Y&lkVUSUTzdIexqS_pRsO{T1k$p7uNmBsqOzZ_3-XS6@GWS6;tu+cxw4 zVaq@NTKewY_Zz#rv(-R>VtIe@IEKe17(nABTIr?6G^HcP9MVS(2Z*a_==h#gxczo4#s&o1-*IMRJma n^8x-15d#>~=+W)*{}a2^iWD~OeRJ0WlOcnrtDnm{r-UW|>Jt{< diff --git a/examples/widgets/draganddrop/puzzle/example.jpg b/examples/widgets/draganddrop/puzzle/example.jpg index e09fb7075700b457d90e845fef814158bc2641d1..023203c57aa838e7a5df22a27bde37b909667c1e 100644 GIT binary patch literal 42654 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 z%0D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 yahI3uL*Ebwe7#c}81|KIb!<{yy%oBuDuZzQ|` diff --git a/examples/widgets/graphicsview/boxes/qt-logo.jpg b/examples/widgets/graphicsview/boxes/qt-logo.jpg index 4014b4659c1100c4a07cb562a3647fcfbb5f1cdd..8d7fab052a0b32c0adfcc18d8086faf9f8021598 100644 GIT binary patch literal 20316 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 Le{{upJ@fwo23FG3 literal 40886 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 literal 13923 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 z%0D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 yahI3uL*Ebwe7#c}81|KIb!<{yy%oBuDuZzQ|` diff --git a/examples/widgets/painting/basicdrawing/images/qt-logo.png b/examples/widgets/painting/basicdrawing/images/qt-logo.png index a8b452e07a5b7d55cc71121132a23c16e58725b6..abfc8caadbbcd3d1c57ad4e15db32216b23f7e1d 100644 GIT binary patch delta 1817 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 O0000JB^A9CWEa>{NHi5y-AP1VqlY zhn?zy+(VAF2b@77P;sYPkgQYNF+U(#dk84y2r>aI2vpN>$Qj6O_}>5&0UF+V)Mwh+ zw9U6C{QLj!;G?DWzyAJcIPB7R*zL!kulpV>xc}io`!WBozdnBZ{psEJ=NDh@dGO(4 z%Te#2f4-e~y1wf~NcV}*wKv+Po=s^!;<@Zg&TLSE?R=y7uMQ`%}+0&A(Lq=;M{=Uv9sz|M6ni zy;*<%{jERb+<82x;jrtUf4{%1+I<8VEOI45e!&bZ*EN?``d-|zw(+p-&(NoT3%*@g zROT&nX<2oE3RCB)2`NC8vproLLn`8Y&xP_GHV|x x7cg%>EYIR>eSaefwW^{L9 za%BKPWN%_+AW3auXJt}lVPtu6$z?nM00PuWL_t(|+Kf_NNEA^N{_f1IyF0FJx~{hV zl_^4H8xj3eR%nS4M$*qqpR2GeT9h_&tkjXDDg$cI&YNiFo1b^fp5-n*knCPUG0Ad#z5eP~U z4Lq8kG@_}q9>YEt0^_Qa6p?Zol5_j+9hN9ZU|%|AI*f=3Jpvt?u0ajU=;?Wf3&l5J zv)kG6##uz!k&^om%!s1q`VI^Erbn- zP5zGS%@=X$;8mFjA;PuF`E!u_U85vlbl|7eW$jBi$&<>6{tYk;L9iO>} zsCaM|jyOAd$GYK2h{HFf8?r3HYT^+m3KV<<%ztM*OTg1jLRB=R*;6pgwV<};qP;Qv*Ys&JvyRLjKEk(!T!+c+Q^Vm`UvxU!{fa&cd4 z6By=;B+GQjKozxLP?S;Isf9^qOjLYcL(zxh^xfCEx_$5cQ+`~&b_HIq_czUW!nW`) zVJ}bi$f3j4e>)fOAJX-@3vT!5AH2h{1V05B0N8CM1`#qdj{pDw07*qoM6N<$f+)Lw ASO5S3 diff --git a/examples/widgets/widgets/icons/images/qt_extended_32x32.png b/examples/widgets/widgets/icons/images/qt_extended_32x32.png index 7b7a790c122392b551904fc21fd31c2e7f331acd..6e7d000c0470e0f45ae714827ba72f69cc25270a 100644 GIT binary patch delta 880 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 Ll#2rm;d|?EtfwxK literal 5149 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 diff --git a/src/tools/qlalr/doc/src/images/qt-logo.png b/src/tools/qlalr/doc/src/images/qt-logo.png index 2dc67161c1b8a27686b4bfa9666c6752bb6f6c36..6e7d000c0470e0f45ae714827ba72f69cc25270a 100644 GIT binary patch delta 880 zcmeC<{=+swvYwfNfx%@-*D(eL#(4ogA+G=b|F1jbRDZ~^;c6&|aoDNukaO)J=iF_c zwFe!6B6WwIY7V;89RjiIfm|qZt~&^lsy*V^u-~EVh&514El3Ke%(3B^J49K-A!n%i zgU&!Jst>x=1GNF|s0En_G0PcfP3>Vvs5sD+gD!=~EFsSN_y6CQU+;hY{n2pPrR|ts z!(rE!qh9UD{O4ZGKl6O+#M5z$E|)+2c)96_`=gIn>km2Ke0%)lvki@h-JXBBbLi2s z%dhrtyE|plnS|G0AHMzm^v9pC6YEdMe)#dS>4?Y0mwT36sp>uvy6#5D##_B-pKsfF zZ|1k(pML-Sx$1h;`4>A^UvK{Y`}3{0Cnlds>^~K?=0@wKS9@Q5eb8|{@b3Gw6Hdi+ z9uHc7v$N+!*p7SCZ@fABEC~UPdr_J|HFl@6T$DlKc8?q_W76F z=U(hsajm{#?TxngKVEbk4|w|d=IwWD$2#hnMk|4iehTpAhf0nL^U=O=_U31CZ*;iIIHH2!j@K&v_4HkOv zOYhy+k&h=Ue-ltOB`1=4$9Ne0;e>;oI}$=g)nep?{;6=fLd_=Cu782l6*m z|5gweJGr2#gO}gc?15)Z{ncv?bqb1`7`nX=eCiTcX*8V}pRiPS!EtV@gJ-(_FdP3D zSyaFGfpNsS7iNj48DClVJesE^#*=YSfv5AbK~IJw+q1cXhu?R(JH$NU6}Z}@_h7#V zlbb8ITEmv#0mfAZY0lG6SXb!FC+xq?{Y28HexeD`H{ojQ%|!+7u^qTonEAmX&5u#& z?r)CA^JC`Dx>C1ObH=o!=b{2Xx$bXb4OqwU(~dovHDDzZ=kiDGKMuJ%vmU*>E2Q$~ zg+_;~Q&%6%zW27|;8$sL@BF)blDFR7*<1dpHJLy4;W7jp00i_>zopr E01%?-761SM delta 1414 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 From 8545821bf8c3694d0dcb5293f3b23fef2d90cd02 Mon Sep 17 00:00:00 2001 From: Aki Koskinen Date: Tue, 23 Sep 2014 14:09:21 +0300 Subject: [PATCH 142/323] Fix incorrect documentation from QTranslator::load Task-number: QTBUG-27506 Change-Id: I1b2d4ed2242efd52258c7f587c2121f9dde18a0d Reviewed-by: Oswald Buddenhagen --- src/corelib/kernel/qtranslator.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index 33827926c6..dc56ad88a1 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -426,9 +426,8 @@ QTranslator::~QTranslator() directory. Returns \c true if the translation is successfully loaded; otherwise returns \c false. - If \a directory is not specified, the directory of the - application's executable is used (i.e., as - \l{QCoreApplication::}{applicationDirPath()}). + If \a directory is not specified, the current directory is used + (i.e., as \l{QDir::}{currentPath()}). The previous contents of this translator object are discarded. From a2ce7e6a6f0f5c638aaa644255e9352eb91b57d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 9 May 2014 09:40:19 +0200 Subject: [PATCH 143/323] Cocoa: Don't activate popup windows. Qt expects a handleWindowActivated call for non- popup windows only. Add a window type check, similar to the other handleWindowActivated calls. Task-number: QTBUG-38707 Change-Id: Iaa5959675f7e3ae4664bdf785d3f374debb0d0a7 Reviewed-by: Friedemann Kleint Reviewed-by: Gabriel de Dietrich Reviewed-by: Liang Qi --- src/plugins/platforms/cocoa/qnsview.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index fa85a2bf54..83e913ad58 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -603,7 +603,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; { if (m_window->flags() & Qt::WindowTransparentForInput) return NO; - QWindowSystemInterface::handleWindowActivated([self topLevelWindow]); + if (!m_platformWindow->windowIsPopupType()) + QWindowSystemInterface::handleWindowActivated([self topLevelWindow]); return YES; } From bb31aa853eb704bc916004ea59ad57bc6baa1276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 30 Oct 2014 16:52:36 +0100 Subject: [PATCH 144/323] Cocoa: refactor commit 876a428f. Conditions for when updateExposedGeometry() should actually send the expose event goes into the function itself. The window()->isVisible() check could arguably be moved to isWindowExposable(), but I'm keeping this as a straight refactor without any behavior changes. (isWindowExposable() is called from multiple locations) Change-Id: I6d792286ccbc50065ebfc588daca2240761a1937 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/cocoa/qcocoawindow.mm | 5 +++++ src/plugins/platforms/cocoa/qnsview.mm | 8 ++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index f536e20b39..56c356711e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1754,6 +1754,11 @@ void QCocoaWindow::updateExposedGeometry() if (!m_geometryUpdateExposeAllowed) return; + // Do not send incorrect exposes in case the window is not even visible yet. + // We might get here as a result of a resize() from QWidget's show(), for instance. + if (!window()->isVisible()) + return; + if (!isWindowExposable()) return; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 83e913ad58..052a7cc98f 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -361,12 +361,8 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; // Send a geometry change event to Qt, if it's ready to handle events if (!m_platformWindow->m_inConstructor) { QWindowSystemInterface::handleGeometryChange(m_window, geometry); - // Do not send incorrect exposes in case the window is not even visible yet. - // We might get here as a result of a resize() from QWidget's show(), for instance. - if (m_platformWindow->window()->isVisible()) { - m_platformWindow->updateExposedGeometry(); - QWindowSystemInterface::flushWindowSystemEvents(); - } + m_platformWindow->updateExposedGeometry(); + QWindowSystemInterface::flushWindowSystemEvents(); } } From 7146cbed6e3a42389593b775bf4a26f05b4b8d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 22 Oct 2014 00:41:55 +0200 Subject: [PATCH 145/323] Cocoa: Guard against recursive event delivery Fix "Recursive repaint" crash. Add guard to QCococaWindow::setGeometry and QNSView updateGeometry to prevent processing window system events during setGeometry. Task-number: QTBUG-41449 Change-Id: I304fdf134d433cbc50fafd997ecd91e31cb57f4e Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 3 +++ src/plugins/platforms/cocoa/qnsview.mm | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index a43cf73d34..b232c7a4d3 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -268,6 +268,7 @@ public: // for QNSView bool m_inConstructor; bool m_inSetVisible; + bool m_inSetGeometry; #ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; #endif diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 56c356711e..6656212457 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -381,6 +381,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_windowUnderMouse(false) , m_inConstructor(true) , m_inSetVisible(false) + , m_inSetGeometry(false) #ifndef QT_NO_OPENGL , m_glContext(0) #endif @@ -470,6 +471,8 @@ QSurfaceFormat QCocoaWindow::format() const void QCocoaWindow::setGeometry(const QRect &rectIn) { + QBoolBlocker inSetGeometry(m_inSetGeometry, true); + QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 052a7cc98f..de30972393 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -362,7 +362,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (!m_platformWindow->m_inConstructor) { QWindowSystemInterface::handleGeometryChange(m_window, geometry); m_platformWindow->updateExposedGeometry(); - QWindowSystemInterface::flushWindowSystemEvents(); + // Guard against processing window system events during QWindow::setGeometry + // calles, which Qt and Qt applications do not excpect. + if (!m_platformWindow->m_inSetGeometry) + QWindowSystemInterface::flushWindowSystemEvents(); } } From 63c7ceaf1b352efa4c6d5a6be96819d6e013e2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 30 Oct 2014 17:00:03 +0100 Subject: [PATCH 146/323] Revert "OS X - unified toolbar and AA_NativeWindows" Will be fixed in a different way. This reverts commit ae5f3df59b37e0ce8aaef27dc1e02f40def340ae. Change-Id: Ie706396667a5b6c9003bb92a018d88346a180e65 Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qnsview.mm | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index de30972393..09368fa25e 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -676,23 +676,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->m_forwardWindow = 0; } - NSPoint globalPos = [NSEvent mouseLocation]; - - if ([self.window parentWindow] - && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) { - // QToolBar can be implemented as a child window on top of its main window - // (with a borderless NSWindow). If an option "unified toolbar" set on the main window, - // it's possible to drag such a window using this toolbar. - // While handling mouse drag events, QToolBar moves the window (QWidget::move). - // In such a combination [NSEvent mouseLocation] is very different from the - // real event location and as a result a window will move chaotically. - NSPoint winPoint = [theEvent locationInWindow]; - NSRect tmpRect = NSMakeRect(winPoint.x, winPoint.y, 1., 1.); - tmpRect = [[theEvent window] convertRectToScreen:tmpRect]; - globalPos = tmpRect.origin; - } - - [targetView convertFromScreen:globalPos toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); From 39be577cc2dee415129d34afffc0b3509371db68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 9 May 2014 11:22:34 +0200 Subject: [PATCH 147/323] Cocoa: get mouse position from event if possible ...instead of using the current mouse position. This is important if event processing is delayed: we want the QMouseEvent to have the position when the event happened, not the current position. Regression from Qt 4. Change-Id: Ifd4f0f02853236a204de96c5a97e72f86c29f0b7 Task-id: QTBUG-37926 Reviewed-by: Timur Pocheptsov Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qnsview.mm | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 09368fa25e..699340795d 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -662,6 +662,19 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_frameStrutButtons = Qt::NoButton; } +- (NSPoint) screenMousePoint:(NSEvent *)theEvent +{ + NSPoint screenPoint; + if (theEvent) { + NSPoint windowPoint = [theEvent locationInWindow]; + NSRect screenRect = [[theEvent window] convertRectToScreen:NSMakeRect(windowPoint.x, windowPoint.y, 1, 1)]; + screenPoint = screenRect.origin; + } else { + screenPoint = [NSEvent mouseLocation]; + } + return screenPoint; +} + - (void)handleMouseEvent:(NSEvent *)theEvent { [self handleTabletEvent: theEvent]; @@ -676,7 +689,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->m_forwardWindow = 0; } - [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + [targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); @@ -849,7 +862,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; QPointF windowPoint; QPointF screenPoint; - [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; QWindow *childWindow = m_platformWindow->childWindowAt(windowPoint.toPoint()); // Top-level windows generate enter-leave events for sub-windows. From 063a54461677c0dbf75282bc367f204af792dac2 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 30 Oct 2014 14:19:32 +0100 Subject: [PATCH 148/323] iOS: remove unused function 'fromPortraitToPrimary' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ic768790a90ef7048bd5e7027e9682988085368fe Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosglobal.h | 2 +- src/plugins/platforms/ios/qiosglobal.mm | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index dbedba7e85..f7b9cd7015 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -62,7 +62,7 @@ QPointF fromCGPoint(const CGPoint &point); Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation); UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation); -QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen); + int infoPlistValue(NSString* key, int defaultValue); QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 71d5a58088..9f10c3e287 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -127,15 +127,6 @@ UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation) return uiOrientation; } -QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen) -{ - // UIScreen is always in portrait. Use this function to convert CGRects - // aligned with UIScreen into whatever is the current orientation of QScreen. - QRect geometry = screen->geometry(); - return geometry.width() < geometry.height() ? rect - : QRect(rect.y(), geometry.height() - rect.width() - rect.x(), rect.height(), rect.width()); -} - int infoPlistValue(NSString* key, int defaultValue) { static NSBundle *bundle = [NSBundle mainBundle]; From 8a9addf42ef1577d5ae337a9a45ef2f2c585afc0 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Tue, 4 Nov 2014 13:51:53 -0800 Subject: [PATCH 149/323] QMenu check for null result from QPlatformMenu::menuItemForTag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QMenu needs to check result of QPlatformMenu::menuItemForTag to avoid a crash dereferencing a null pointer. Task-number: QTBUG-42327 Change-Id: Ie54a94caec7a5d756c459741df182fbe4e38bec0 Reviewed-by: Morten Johan Sørvig --- src/widgets/widgets/qmenu.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 0fd645a4d3..acfccc8e19 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -3055,8 +3055,10 @@ void QMenu::actionEvent(QActionEvent *e) delete menuItem; } else if (e->type() == QEvent::ActionChanged) { QPlatformMenuItem *menuItem = d->platformMenu->menuItemForTag(reinterpret_cast(e->action())); - copyActionToPlatformItem(e->action(), menuItem); - d->platformMenu->syncMenuItem(menuItem); + if (menuItem) { + copyActionToPlatformItem(e->action(), menuItem); + d->platformMenu->syncMenuItem(menuItem); + } } d->platformMenu->syncSeparatorsCollapsible(d->collapsibleSeparators); From 7eb7dd555cc50112ae242a32976f075f070625d7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 5 Nov 2014 07:31:01 +0100 Subject: [PATCH 150/323] Documentation CSS: remove body text color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Help text should use the QPalette color. Task-number: QTBUG-42399 Change-Id: Ibc8658b4a7affc2481d895c13cfa673b50a872e0 Reviewed-by: Topi Reiniö --- doc/global/template/style/offline.css | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/global/template/style/offline.css b/doc/global/template/style/offline.css index 5957e3840d..126df9d806 100644 --- a/doc/global/template/style/offline.css +++ b/doc/global/template/style/offline.css @@ -2,7 +2,6 @@ body { font: normal 400 14px/1.2 Arial; margin-top: 85px; font-family: Arial, Helvetica; - color: #313131; text-align: left; margin-left: 5px; margin-right: 5px; From 47ec22a50975d6f616043fc12424ae1e12e584bd Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Tue, 14 Oct 2014 16:55:17 +0200 Subject: [PATCH 151/323] Allow panels outside of availableGeometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Panels windows are usually outside QScreen::availableGeometry, because they will usually set extended struts to reserve the screen area for themselves, but their own screen() must remain the one in which they are. This cause one downstream behavior to KDE https://bugs.kde.org/show_bug.cgi?id=339846 in which a panel got by mistake few pixels on another screen, and was immediately reassigned to that screen, because its geometry was intersecting the new screen availableGeometry() but not the geometry of its own screen, because itself reserved its own geometry away from availableGeometry() Change-Id: If6c9defdef62732473687dd336dbcec582bd0ea2 Reviewed-by: Jørgen Lind --- src/plugins/platforms/xcb/qxcbwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 586068d8d9..a99a5cfab5 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1687,9 +1687,9 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); - if (!m_screen->availableGeometry().intersects(rect)) { + if (!m_screen->geometry().intersects(rect)) { Q_FOREACH (QPlatformScreen* screen, m_screen->virtualSiblings()) { - if (screen->availableGeometry().intersects(rect)) { + if (screen->geometry().intersects(rect)) { m_screen = static_cast(screen); QWindowSystemInterface::handleWindowScreenChanged(window(), m_screen->QPlatformScreen::screen()); break; From 2b9a793dcd7a4abcad29c817eb92443a325e789b Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Sat, 1 Nov 2014 22:27:56 +0200 Subject: [PATCH 152/323] Set the _C variants of QMAKE_LINK and QMAKE_LINK_SHLIB in clang.conf. While it does not look like the clang-based mkspecs had any problems so far with not having QMAKE_LINK_C and QMAKE_LINK_C_SHLIB defined, it makes sense to set them to $$QMAKE_CC just like the GCC-based ones so CONFIG=use_c_linker works as expected. Change-Id: Ib660d12b001dd7a877b6f03e79715db08a272968 Reviewed-by: Gabriel de Dietrich Reviewed-by: Oswald Buddenhagen --- mkspecs/common/clang.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf index d58b44b295..d6418b54b3 100644 --- a/mkspecs/common/clang.conf +++ b/mkspecs/common/clang.conf @@ -7,6 +7,9 @@ QMAKE_COMPILER = gcc clang llvm # clang pretends to be gcc QMAKE_CC = clang QMAKE_CXX = clang++ +QMAKE_LINK_C = $$QMAKE_CC +QMAKE_LINK_C_SHLIB = $$QMAKE_CC + QMAKE_LINK = $$QMAKE_CXX QMAKE_LINK_SHLIB = $$QMAKE_CXX From cfa73537cc6a3687566094442cf15771f01ef431 Mon Sep 17 00:00:00 2001 From: Raphael Kubo da Costa Date: Sat, 1 Nov 2014 17:57:41 +0200 Subject: [PATCH 153/323] Stop including g++-unix.conf in the freebsd-clang mkspec. Most of the settings there end up overwritten by the clang.conf include that comes afterwards, except for a few things such as QMAKE_LINK_C, which remains set to "gcc" and breaks things when one uses CONFIG=use_c_linker. QMAKE_LFLAGS_NOUNDEF was coming from g++-unix.conf, though, so we now manually set it in freebsd-clang's qmake.conf. Change-Id: Ibd16f59d43eb19e72adf4919da9ce3007100b60f Reviewed-by: Gabriel de Dietrich Reviewed-by: Oswald Buddenhagen --- mkspecs/unsupported/freebsd-clang/qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/unsupported/freebsd-clang/qmake.conf b/mkspecs/unsupported/freebsd-clang/qmake.conf index ad4fa3487e..2cfd763688 100644 --- a/mkspecs/unsupported/freebsd-clang/qmake.conf +++ b/mkspecs/unsupported/freebsd-clang/qmake.conf @@ -13,6 +13,7 @@ QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD QMAKE_INCDIR = /usr/local/include QMAKE_LIBDIR = /usr/local/lib +QMAKE_LFLAGS_NOUNDEF = -Wl,--no-undefined QMAKE_LFLAGS_THREAD = -pthread QMAKE_LIBS = @@ -28,6 +29,5 @@ QMAKE_RANLIB = include(../../common/unix.conf) include(../../common/gcc-base-unix.conf) -include(../../common/g++-unix.conf) include(../../common/clang.conf) load(qt_config) From b7d36614e9f00a3376dd19493eaf3ffc4ec431da Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 30 Oct 2014 20:18:48 +0100 Subject: [PATCH 154/323] Remove incorrect execute file permissions from source files Amends commit 9c3a58a913a7e59359146264ee59d40d703d4db2. Change-Id: I292eb9df480a642a65f9065e4fe36bd52c093dc7 Reviewed-by: Oswald Buddenhagen --- tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro | 0 tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro mode change 100755 => 100644 tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp diff --git a/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro b/tests/auto/widgets/kernel/qwidget_window/qwidget_window.pro old mode 100755 new mode 100644 diff --git a/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp b/tests/auto/widgets/kernel/qwidget_window/tst_qwidget_window.cpp old mode 100755 new mode 100644 From 54d4fb4f500dfb45d86b2046b90becd55783e48e Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 30 Sep 2014 09:52:51 +0200 Subject: [PATCH 155/323] Fix QString::sprintf documentation QString::sprintf does actually support all length modifiers, including %lld. The format string is also parsed as UTF-8. What's worthwile to mention, though, is that %lc and %ls is at odds with the standard, since wchar_t isn't necessarily 16 bits wide. Change-Id: I30cd22ec5b42035824dd98e3cdcc79d7adcc953a Reviewed-by: Olivier Goffart Reviewed-by: Thiago Macieira --- src/corelib/doc/snippets/qstring/main.cpp | 8 -------- src/corelib/tools/qstring.cpp | 25 ++++++++++------------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/corelib/doc/snippets/qstring/main.cpp b/src/corelib/doc/snippets/qstring/main.cpp index bf45a31c29..f49c4dd359 100644 --- a/src/corelib/doc/snippets/qstring/main.cpp +++ b/src/corelib/doc/snippets/qstring/main.cpp @@ -760,14 +760,6 @@ void Widget::splitCaseSensitiveFunction() void Widget::sprintfFunction() { - //! [63] - size_t BufSize; - char buf[BufSize]; - - ::snprintf(buf, BufSize, "%lld", 123456789LL); - QString str = QString::fromUtf8(buf); - //! [63] - //! [64] QString result; QTextStream(&result) << "pi = " << 3.14; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 3b18d31547..7d0607a2f7 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -5692,21 +5692,18 @@ QString QString::toUpper() const Safely builds a formatted string from the format string \a cformat and an arbitrary list of arguments. - The %lc escape sequence expects a unicode character of type ushort - (as returned by QChar::unicode()). The %ls escape sequence expects - a pointer to a zero-terminated array of unicode characters of type - ushort (as returned by QString::utf16()). + The format string supports the conversion specifiers, length modifiers, + and flags provided by printf() in the standard C++ library. The \a cformat + string and \c{%s} arguments must be UTF-8 encoded. - \note This function expects a UTF-8 string for %s and Latin-1 for - the format string. - - The format string supports most of the conversion specifiers - provided by printf() in the standard C++ library. It doesn't - honor the length modifiers (e.g. \c h for \c short, \c ll for - \c{long long}). If you need those, use the standard snprintf() - function instead: - - \snippet qstring/main.cpp 63 + \note The \c{%lc} escape sequence expects a unicode character of type + \c char16_t, or \c ushort (as returned by QChar::unicode()). + The \c{%ls} escape sequence expects a pointer to a zero-terminated array + of unicode characters of type \c char16_t, or ushort (as returned by + QString::utf16()). This is at odds with the printf() in the standard C++ + library, which defines \c {%lc} to print a wchar_t and \c{%ls} to print + a \c{wchar_t*}, and might also produce compiler warnings on platforms + where the size of \c {wchar_t} is not 16 bits. \warning We do not recommend using QString::sprintf() in new Qt code. Instead, consider using QTextStream or arg(), both of From 6a2bdc4ee2dc49b5d89d09a1f255a7a0e2f18acf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 28 Oct 2014 17:23:09 -0700 Subject: [PATCH 156/323] Always lock the DBus dispatcher before dbus_connection_send* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We lock it before dbus_connection_send_with_reply (the async version) in QDBusConnectionPrivate::sendWithReplyAsync. We weren't locking it before send_with_reply_and_block and we apparently should. The locking around the dbus_connection_send function might not be necessary, but let's do it to be safe. The lock now needs to be recursive because we may be inside QDBusConnectionPrivate::doDispatch. Task-number: QTBUG-42189 Change-Id: I7b6b350909359817ea8b3f9c693bced042c9779a Reviewed-by: Jędrzej Nowacki Reviewed-by: Frederik Gladhorn --- src/dbus/qdbusintegrator.cpp | 19 +++++++++++++++---- src/dbus/qdbusthreaddebug_p.h | 3 +++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 499e9dbd82..b2f6635d1b 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1017,7 +1017,7 @@ extern bool qDBusInitThreads(); QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p) : QObject(p), ref(1), capabilities(0), mode(InvalidMode), connection(0), server(0), busService(0), - watchAndTimeoutLock(QMutex::Recursive), + watchAndTimeoutLock(QMutex::Recursive), dispatchLock(QMutex::Recursive), rootNode(QString(QLatin1Char('/'))), anonymousAuthenticationAllowed(false) { @@ -1266,7 +1266,10 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in //qDBusDebug() << "Emitting signal" << message; //qDBusDebug() << "for paths:"; q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything - huntAndEmit(connection, msg, obj, rootNode, isScriptable, isAdaptor); + { + QDBusDispatchLocker locker(HuntAndEmitAction, this); + huntAndEmit(connection, msg, obj, rootNode, isScriptable, isAdaptor); + } q_dbus_message_unref(msg); } @@ -1923,7 +1926,11 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message) qDBusDebug() << this << "sending message (no reply):" << message; checkThread(); - bool isOk = q_dbus_connection_send(connection, msg, 0); + bool isOk; + { + QDBusDispatchLocker locker(SendMessageAction, this); + isOk = q_dbus_connection_send(connection, msg, 0); + } int serial = 0; if (isOk) serial = q_dbus_message_get_serial(msg); @@ -1955,7 +1962,11 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, qDBusDebug() << this << "sending message (blocking):" << message; QDBusErrorInternal error; - DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error); + DBusMessage *reply; + { + QDBusDispatchLocker locker(SendWithReplyAndBlockAction, this); + reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error); + } q_dbus_message_unref(msg); diff --git a/src/dbus/qdbusthreaddebug_p.h b/src/dbus/qdbusthreaddebug_p.h index f9039ef3cd..dcde99169c 100644 --- a/src/dbus/qdbusthreaddebug_p.h +++ b/src/dbus/qdbusthreaddebug_p.h @@ -94,6 +94,9 @@ enum ThreadAction { MessageResultReceivedAction = 26, ActivateSignalAction = 27, PendingCallBlockAction = 28, + SendMessageAction = 29, + SendWithReplyAndBlockAction = 30, + HuntAndEmitAction = 31, AddTimeoutAction = 50, RealAddTimeoutAction = 51, From eb99c28861f5e841f306cfe8689627fe0e9bf2e8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 28 Oct 2014 19:26:17 -0700 Subject: [PATCH 157/323] QDBusConnection: Merge the dispatch and the watch-and-timeout locks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need two anymore because they now protect the same thing: the state of the DBusConnection. The difference existed when it was possible for two threads to access the DBusConnection at the same time: one doing dispatching and one doing something else. Unfortunately, even though DBusConnection supports this, QtDBus doesn't. From d47c05b1889bb4f06203bbc65f4660b8d0128954 (2008-10-08): Details: if we're removing a timer or a watcher from our list, there's a race condition: one thread (not the QDBusConnection thread) could be asking for the removal (which causes an event to be sent), then deletes the pointer. In the meantime, QDBusConnection will process the timers and socket notifiers and could end up calling lidbus-1 with deleted pointers. That commit fixed the race condition but introduced a deadlock. Task-number: QTBUG-42189 Change-Id: I034038f763cbad3a67398909defd31a23c27c965 Reviewed-by: Jędrzej Nowacki Reviewed-by: Albert Astals Cid Reviewed-by: Frederik Gladhorn --- src/dbus/qdbusconnection_p.h | 18 ++++++------------ src/dbus/qdbusintegrator.cpp | 22 +++++++++++----------- src/dbus/qdbusthreaddebug_p.h | 7 ------- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index fd4ced078d..a75dabeeee 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -290,24 +290,18 @@ public: QStringList serverConnectionNames; ConnectionMode mode; - - // members accessed in unlocked mode (except for deletion) - // connection and server provide their own locking mechanisms - // busService doesn't have state to be changed - DBusConnection *connection; - DBusServer *server; QDBusConnectionInterface *busService; - // watchers and timeouts are accessed from any thread - // but the corresponding timer and QSocketNotifier must be handled - // only in the object's thread - QMutex watchAndTimeoutLock; + // the dispatch lock protects everything related to the DBusConnection or DBusServer + // including the timeouts and watches + QMutex dispatchLock; + DBusConnection *connection; + DBusServer *server; WatcherHash watchers; TimeoutHash timeouts; PendingTimeoutList timeoutsPendingAdd; - // members accessed through a lock - QMutex dispatchLock; + // the master lock protects our own internal state QReadWriteLock lock; QDBusError lastError; diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index b2f6635d1b..39ab797426 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -155,7 +155,7 @@ static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data) if (!q_dbus_timeout_get_enabled(timeout)) return true; - QDBusWatchAndTimeoutLocker locker(AddTimeoutAction, d); + QDBusDispatchLocker locker(AddTimeoutAction, d); if (QCoreApplication::instance() && QThread::currentThread() == d->thread()) { // correct thread return qDBusRealAddTimeout(d, timeout, q_dbus_timeout_get_interval(timeout)); @@ -190,7 +190,7 @@ static void qDBusRemoveTimeout(DBusTimeout *timeout, void *data) QDBusConnectionPrivate *d = static_cast(data); - QDBusWatchAndTimeoutLocker locker(RemoveTimeoutAction, d); + QDBusDispatchLocker locker(RemoveTimeoutAction, d); // is it pending addition? QDBusConnectionPrivate::PendingTimeoutList::iterator pit = d->timeoutsPendingAdd.begin(); @@ -263,7 +263,7 @@ static bool qDBusRealAddWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int f { QDBusConnectionPrivate::Watcher watcher; - QDBusWatchAndTimeoutLocker locker(AddWatchAction, d); + QDBusDispatchLocker locker(AddWatchAction, d); if (flags & DBUS_WATCH_READABLE) { //qDebug("addReadWatch %d", fd); watcher.watch = watch; @@ -297,7 +297,7 @@ static void qDBusRemoveWatch(DBusWatch *watch, void *data) QDBusConnectionPrivate *d = static_cast(data); int fd = q_dbus_watch_get_unix_fd(watch); - QDBusWatchAndTimeoutLocker locker(RemoveWatchAction, d); + QDBusDispatchLocker locker(RemoveWatchAction, d); QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); while (i != d->watchers.end() && i.key() == fd) { if (i.value().watch == watch) { @@ -341,7 +341,7 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data) static void qDBusRealToggleWatch(QDBusConnectionPrivate *d, DBusWatch *watch, int fd) { - QDBusWatchAndTimeoutLocker locker(ToggleWatchAction, d); + QDBusDispatchLocker locker(ToggleWatchAction, d); QDBusConnectionPrivate::WatcherHash::iterator i = d->watchers.find(fd); while (i != d->watchers.end() && i.key() == fd) { @@ -1016,8 +1016,8 @@ void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const Q extern bool qDBusInitThreads(); QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p) - : QObject(p), ref(1), capabilities(0), mode(InvalidMode), connection(0), server(0), busService(0), - watchAndTimeoutLock(QMutex::Recursive), dispatchLock(QMutex::Recursive), + : QObject(p), ref(1), capabilities(0), mode(InvalidMode), busService(0), + dispatchLock(QMutex::Recursive), connection(0), server(0), rootNode(QString(QLatin1Char('/'))), anonymousAuthenticationAllowed(false) { @@ -1127,7 +1127,7 @@ bool QDBusConnectionPrivate::handleError(const QDBusErrorInternal &error) void QDBusConnectionPrivate::timerEvent(QTimerEvent *e) { { - QDBusWatchAndTimeoutLocker locker(TimerEventAction, this); + QDBusDispatchLocker locker(TimerEventAction, this); DBusTimeout *timeout = timeouts.value(e->timerId(), 0); if (timeout) q_dbus_timeout_handle(timeout); @@ -1146,7 +1146,7 @@ void QDBusConnectionPrivate::customEvent(QEvent *e) switch (ev->subtype) { case QDBusConnectionCallbackEvent::AddTimeout: { - QDBusWatchAndTimeoutLocker locker(RealAddTimeoutAction, this); + QDBusDispatchLocker locker(RealAddTimeoutAction, this); while (!timeoutsPendingAdd.isEmpty()) { QPair entry = timeoutsPendingAdd.takeFirst(); qDBusRealAddTimeout(this, entry.first, entry.second); @@ -1182,7 +1182,7 @@ void QDBusConnectionPrivate::socketRead(int fd) QVarLengthArray pendingWatches; { - QDBusWatchAndTimeoutLocker locker(SocketReadAction, this); + QDBusDispatchLocker locker(SocketReadAction, this); WatcherHash::ConstIterator it = watchers.constFind(fd); while (it != watchers.constEnd() && it.key() == fd) { if (it->watch && it->read && it->read->isEnabled()) @@ -1202,7 +1202,7 @@ void QDBusConnectionPrivate::socketWrite(int fd) QVarLengthArray pendingWatches; { - QDBusWatchAndTimeoutLocker locker(SocketWriteAction, this); + QDBusDispatchLocker locker(SocketWriteAction, this); WatcherHash::ConstIterator it = watchers.constFind(fd); while (it != watchers.constEnd() && it.key() == fd) { if (it->watch && it->write && it->write->isEnabled()) diff --git a/src/dbus/qdbusthreaddebug_p.h b/src/dbus/qdbusthreaddebug_p.h index dcde99169c..726ab051d0 100644 --- a/src/dbus/qdbusthreaddebug_p.h +++ b/src/dbus/qdbusthreaddebug_p.h @@ -207,13 +207,6 @@ struct QDBusDispatchLocker: QDBusMutexLocker { } }; -struct QDBusWatchAndTimeoutLocker: QDBusMutexLocker -{ - inline QDBusWatchAndTimeoutLocker(ThreadAction a, QDBusConnectionPrivate *s) - : QDBusMutexLocker(a, s, &s->watchAndTimeoutLock) - { } -}; - #if QDBUS_THREAD_DEBUG # define SEM_ACQUIRE(action, sem) \ do { \ From 73a1e8c60d894701f34806cc4b847aa2814bf389 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 28 Oct 2014 19:34:01 -0700 Subject: [PATCH 158/323] Partially revert "Fix a deadlock introduced by the race condition fix" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit was 9361be58f47ec256bf920c378479a02501219c1f (2008-11-17), referring to the race condition fix that was applied in commit d47c05b1889bb4f06203bbc65f4660b8d0128954 (2008-10-08). The fix for the deadlock reintroduced the race condition and the commit message noted it. The workaround is no longer necessary since we've fixed the original race condition differently now (see the previous two commits). Task-number: QTBUG-42189 Change-Id: I5a83249597a83c4d4caa2ae57964ad3cc61c1d70 Reviewed-by: Jędrzej Nowacki Reviewed-by: Albert Astals Cid Reviewed-by: Frederik Gladhorn --- src/dbus/qdbusintegrator.cpp | 40 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 39ab797426..ab0aee355d 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1179,41 +1179,29 @@ void QDBusConnectionPrivate::doDispatch() void QDBusConnectionPrivate::socketRead(int fd) { - QVarLengthArray pendingWatches; - - { - QDBusDispatchLocker locker(SocketReadAction, this); - WatcherHash::ConstIterator it = watchers.constFind(fd); - while (it != watchers.constEnd() && it.key() == fd) { - if (it->watch && it->read && it->read->isEnabled()) - pendingWatches.append(it.value().watch); - ++it; + QDBusDispatchLocker locker(SocketReadAction, this); + WatcherHash::ConstIterator it = watchers.constFind(fd); + while (it != watchers.constEnd() && it.key() == fd) { + if (it->watch && it->read && it->read->isEnabled()) { + if (!q_dbus_watch_handle(it.value().watch, DBUS_WATCH_READABLE)) + qDebug("OUT OF MEM"); } + ++it; } - - for (int i = 0; i < pendingWatches.size(); ++i) - if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_READABLE)) - qDebug("OUT OF MEM"); doDispatch(); } void QDBusConnectionPrivate::socketWrite(int fd) { - QVarLengthArray pendingWatches; - - { - QDBusDispatchLocker locker(SocketWriteAction, this); - WatcherHash::ConstIterator it = watchers.constFind(fd); - while (it != watchers.constEnd() && it.key() == fd) { - if (it->watch && it->write && it->write->isEnabled()) - pendingWatches.append(it.value().watch); - ++it; + QDBusDispatchLocker locker(SocketWriteAction, this); + WatcherHash::ConstIterator it = watchers.constFind(fd); + while (it != watchers.constEnd() && it.key() == fd) { + if (it->watch && it->write && it->write->isEnabled()) { + if (!q_dbus_watch_handle(it.value().watch, DBUS_WATCH_WRITABLE)) + qDebug("OUT OF MEM"); } + ++it; } - - for (int i = 0; i < pendingWatches.size(); ++i) - if (!q_dbus_watch_handle(pendingWatches[i], DBUS_WATCH_WRITABLE)) - qDebug("OUT OF MEM"); } void QDBusConnectionPrivate::objectDestroyed(QObject *obj) From 2d075bf651e246d57d25a95219d7358946b9f785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 4 Nov 2014 17:12:28 +0100 Subject: [PATCH 159/323] iOS: Update integrated event dispatcher to support 64-bit x86 Needed so that we can build simulator builds for x86_64 as well as i386. The function call alignment is the same, but we need to use the 64-bit versions of the instruction and operands. Change-Id: I62cc78e23b5e0923382d19570ce18f558894e6a0 Reviewed-by: Simon Hausmann --- src/plugins/platforms/ios/qioseventdispatcher.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 66fd9cd1e5..ffffc4cbc4 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -317,11 +317,16 @@ static bool rootLevelRunLoopIntegration() } #if defined(Q_PROCESSOR_X86) -# define SET_STACK_POINTER "mov %0, %%esp" # define FUNCTION_CALL_ALIGNMENT 16 +# if defined(Q_PROCESSOR_X86_32) +# define SET_STACK_POINTER "mov %0, %%esp" +# elif defined(Q_PROCESSOR_X86_64) +# define SET_STACK_POINTER "movq %0, %%rsp" +# endif #elif defined(Q_PROCESSOR_ARM) -# define SET_STACK_POINTER "mov sp, %0" +# // Valid for both 32 and 64-bit ARM # define FUNCTION_CALL_ALIGNMENT 4 +# define SET_STACK_POINTER "mov sp, %0" #else # error "Unknown processor family" #endif From ec63f5fbf3927b184f234f95c6003fe8496d8b9f Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 15 Oct 2014 14:00:05 +0200 Subject: [PATCH 160/323] docs: WindowType is important for dialogs to center themselves Task-number: QTBUG-41844 Task-number: QTBUG-36185 Change-Id: I61605006048e81d2666eea34f4d041124a24199f Reviewed-by: Laszlo Agocs --- src/gui/kernel/qwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index b0fbbc1570..99bf469f87 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1122,6 +1122,10 @@ Qt::WindowState QWindow::windowState() const This is a hint to the window manager that this window is a dialog or pop-up on behalf of the given window. + In order to cause the window to be centered above its transient parent by + default, depending on the window manager, it may also be necessary to call + setFlags() with a suitable \l Qt::WindowType (such as \c Qt::Dialog). + \sa transientParent(), parent() */ void QWindow::setTransientParent(QWindow *parent) From 3978249743559d31b793cdfcf77c8e9ae653cec4 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 28 Oct 2014 14:28:42 +0100 Subject: [PATCH 161/323] Doc: add new Qt Creator Manual topics to externalpages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New in some earlier version: - Parsing C++ Files New in Qt Creator 3.3: - Qt Quick UI Forms - Using Clang Static Analyzer Change-Id: I2821b31f4c67b79e6a178018a6acba5b828edb3e Reviewed-by: Topi Reiniö --- doc/global/externalsites/qtcreator.qdoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/global/externalsites/qtcreator.qdoc b/doc/global/externalsites/qtcreator.qdoc index 46609de160..a98fbd0a56 100644 --- a/doc/global/externalsites/qtcreator.qdoc +++ b/doc/global/externalsites/qtcreator.qdoc @@ -483,3 +483,15 @@ \externalpage http://qt-project.org/doc/qtcreator/creator-developing-winrt.html \title Qt Creator: Connecting Windows Runtime Devices */ +/*! + \externalpage http://qt-project.org/doc/qtcreator/creator-clang-codemodel.html + \title Qt Creator: Parsing C++ Files +*/ +/*! + \externalpage http://qt-project.org/doc/qtcreator/creator-quick-ui-forms.html + \title Qt Creator: Qt Quick UI Forms +*/ +/*! + \externalpage http://qt-project.org/doc/qtcreator/creator-clang-static-analyzer.html + \title Qt Creator: Using Clang Static Analyzer +*/ From 7a8bb824ff41228913c2a3e0b969767f3c49c15f Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 27 Oct 2014 12:33:35 +0100 Subject: [PATCH 162/323] Update the copy of the Qml parser The files here are a copy of the parser from the qtdeclarative repository. This patch combines commit cfff375afcfe63d25b3c1904ff58a90bcd1edb43 and f876562de8eb978cea39fe72e76c49ae51ff2f97 from the qtdeclarative repository to fix the license and allow for read-only object property syntax. Change-Id: Idb58948cede2cd47858e3831785009f8b7ea2169 Reviewed-by: Martin Smith --- src/tools/qdoc/qmlparser/qqmljs.g | 117 +- src/tools/qdoc/qmlparser/qqmljsgrammar.cpp | 1712 ++++++++++---------- src/tools/qdoc/qmlparser/qqmljsgrammar_p.h | 12 +- src/tools/qdoc/qmlparser/qqmljsparser.cpp | 456 +++--- src/tools/qdoc/qmlparser/qqmljsparser_p.h | 4 +- 5 files changed, 1164 insertions(+), 1137 deletions(-) diff --git a/src/tools/qdoc/qmlparser/qqmljs.g b/src/tools/qdoc/qmlparser/qqmljs.g index de4fec4d56..616e3b3166 100644 --- a/src/tools/qdoc/qmlparser/qqmljs.g +++ b/src/tools/qdoc/qmlparser/qqmljs.g @@ -1,21 +1,31 @@ ---------------------------------------------------------------------------- -- --- Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +-- Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -- Contact: http://www.qt-project.org/legal -- -- This file is part of the QtQml module of the Qt Toolkit. -- --- $QT_BEGIN_LICENSE:LGPL-ONLY$ --- GNU Lesser General Public License Usage --- This file may be used under the terms of the GNU Lesser --- General Public License version 2.1 as published by the Free Software --- Foundation and appearing in the file LICENSE.LGPL included in the --- packaging of this file. Please review the following information to --- ensure the GNU Lesser General Public License version 2.1 requirements --- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +-- $QT_BEGIN_LICENSE:LGPL21$ +-- 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 Digia. For licensing terms and +-- conditions see http://qt.digia.com/licensing. For further information +-- use the contact form at http://qt.digia.com/contact-us. -- --- If you have questions regarding the use of this file, please contact --- us via http://www.qt-project.org/. +-- GNU Lesser General Public License Usage +-- Alternatively, this file may be used under the terms of the GNU Lesser +-- General Public License version 2.1 or version 3 as published by the Free +-- Software Foundation and appearing in the file LICENSE.LGPLv21 and +-- LICENSE.LGPLv3 included in the packaging of this file. Please review the +-- following information to ensure the GNU Lesser General Public License +-- requirements will be met: https://www.gnu.org/licenses/lgpl.html and +-- http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +-- +-- In addition, as a special exception, Digia gives you certain additional +-- rights. These rights are described in the Digia Qt LGPL Exception +-- version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -- -- $QT_END_LICENSE$ -- @@ -89,41 +99,33 @@ /./**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -142,41 +144,33 @@ /:/**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -1090,6 +1084,31 @@ case $rule_number: { } break; ./ +UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ; +/. +case $rule_number: { + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4)); + propertyName->identifierToken = loc(4); + propertyName->next = 0; + + AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( + propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer); + binding->colonToken = loc(5); + + node->binding = binding; + + sym(1).Node = node; +} break; +./ + UiObjectMember: FunctionDeclaration ; /. case $rule_number: { diff --git a/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp b/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp index d3fb3f8d1f..2600a5e14c 100644 --- a/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp +++ b/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp @@ -57,35 +57,35 @@ const short QQmlJSGrammar::lhs [] = { 130, 130, 130, 130, 130, 130, 130, 111, 138, 138, 138, 139, 139, 140, 140, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, - 111, 111, 124, 124, 124, 124, 124, 124, 124, 143, + 111, 111, 111, 124, 124, 124, 124, 124, 124, 124, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, - 143, 143, 143, 143, 143, 143, 143, 129, 145, 145, - 145, 145, 144, 144, 149, 149, 149, 147, 147, 150, - 150, 150, 150, 153, 153, 153, 153, 153, 153, 153, + 143, 143, 143, 143, 143, 143, 143, 143, 129, 145, + 145, 145, 145, 144, 144, 149, 149, 149, 147, 147, + 150, 150, 150, 150, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 154, 154, 120, 120, 120, 120, - 120, 157, 157, 158, 158, 158, 158, 156, 156, 159, - 159, 160, 160, 161, 161, 161, 162, 162, 162, 162, - 162, 162, 162, 162, 162, 162, 163, 163, 163, 163, - 164, 164, 164, 165, 165, 165, 165, 166, 166, 166, - 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, - 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, - 170, 170, 171, 171, 172, 172, 173, 173, 174, 174, - 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, - 180, 180, 181, 181, 148, 148, 182, 182, 183, 183, + 153, 153, 153, 153, 153, 154, 154, 120, 120, 120, + 120, 120, 157, 157, 158, 158, 158, 158, 156, 156, + 159, 159, 160, 160, 161, 161, 161, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 163, 163, 163, + 163, 164, 164, 164, 165, 165, 165, 165, 166, 166, + 166, 166, 166, 166, 166, 167, 167, 167, 167, 167, + 167, 168, 168, 168, 168, 168, 169, 169, 169, 169, + 169, 170, 170, 171, 171, 172, 172, 173, 173, 174, + 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, + 179, 180, 180, 181, 181, 148, 148, 182, 182, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, - 109, 109, 184, 184, 185, 185, 186, 186, 108, 108, + 183, 109, 109, 184, 184, 185, 185, 186, 186, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 131, 195, 195, 194, 194, 142, 142, - 196, 196, 197, 197, 199, 199, 198, 200, 203, 201, - 201, 204, 202, 202, 132, 133, 133, 134, 134, 187, - 187, 187, 187, 187, 187, 187, 187, 188, 188, 188, - 188, 189, 189, 189, 189, 190, 190, 135, 136, 205, - 205, 208, 208, 206, 206, 209, 207, 191, 192, 192, - 137, 137, 137, 210, 211, 193, 193, 212, 141, 155, - 155, 213, 213, 152, 152, 151, 151, 214, 112, 112, - 215, 215, 110, 110, 146, 146, 216}; + 108, 108, 108, 108, 131, 195, 195, 194, 194, 142, + 142, 196, 196, 197, 197, 199, 199, 198, 200, 203, + 201, 201, 204, 202, 202, 132, 133, 133, 134, 134, + 187, 187, 187, 187, 187, 187, 187, 187, 188, 188, + 188, 188, 189, 189, 189, 189, 190, 190, 135, 136, + 205, 205, 208, 208, 206, 206, 209, 207, 191, 192, + 192, 137, 137, 137, 210, 211, 193, 193, 212, 141, + 155, 155, 213, 213, 152, 152, 151, 151, 214, 112, + 112, 215, 215, 110, 110, 146, 146, 216}; const short QQmlJSGrammar::rhs [] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, @@ -95,110 +95,110 @@ const short QQmlJSGrammar::rhs [] = { 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 1, 2, 4, 6, 6, 3, 3, 7, 7, 4, 4, 5, 5, 5, 6, 6, 10, 6, + 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 3, 3, 4, 5, 3, 4, 3, 1, 1, 2, - 3, 4, 1, 2, 3, 7, 8, 1, 3, 1, + 2, 3, 3, 4, 5, 3, 4, 3, 1, 1, + 2, 3, 4, 1, 2, 3, 7, 8, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 4, 3, - 5, 1, 2, 4, 4, 4, 3, 0, 1, 1, - 3, 1, 1, 1, 2, 2, 1, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 3, 3, 3, - 1, 3, 3, 1, 3, 3, 3, 1, 3, 3, - 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, - 1, 3, 3, 3, 3, 1, 3, 3, 3, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 5, 1, 5, 1, 3, 1, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, + 3, 5, 1, 2, 4, 4, 4, 3, 0, 1, + 1, 3, 1, 1, 1, 2, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 3, 3, + 3, 1, 3, 3, 1, 3, 3, 3, 1, 3, + 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, + 3, 1, 3, 3, 3, 3, 1, 3, 3, 3, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 5, 1, 5, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 0, 1, 1, 3, 0, 1, 1, 1, + 1, 1, 3, 0, 1, 1, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 2, 0, 1, 3, 3, - 1, 1, 1, 3, 1, 3, 2, 2, 2, 0, - 1, 2, 0, 1, 1, 2, 2, 7, 5, 7, - 7, 7, 5, 9, 10, 7, 8, 2, 2, 3, - 3, 2, 2, 3, 3, 3, 3, 5, 5, 3, - 5, 1, 2, 0, 1, 4, 3, 3, 3, 3, - 3, 3, 4, 5, 2, 2, 2, 1, 8, 8, - 7, 1, 3, 0, 1, 0, 1, 1, 1, 1, - 1, 2, 1, 1, 0, 1, 2}; + 1, 1, 1, 1, 3, 1, 2, 0, 1, 3, + 3, 1, 1, 1, 3, 1, 3, 2, 2, 2, + 0, 1, 2, 0, 1, 1, 2, 2, 7, 5, + 7, 7, 7, 5, 9, 10, 7, 8, 2, 2, + 3, 3, 2, 2, 3, 3, 3, 3, 5, 5, + 3, 5, 1, 2, 0, 1, 4, 3, 3, 3, + 3, 3, 3, 4, 5, 2, 2, 2, 1, 8, + 8, 7, 1, 3, 0, 1, 0, 1, 1, 1, + 1, 1, 2, 1, 1, 0, 1, 2}; const short QQmlJSGrammar::action_default [] = { - 0, 0, 28, 0, 0, 0, 28, 0, 184, 251, - 215, 223, 219, 163, 235, 211, 3, 148, 81, 164, - 227, 231, 152, 181, 162, 167, 147, 201, 188, 0, - 88, 89, 84, 0, 78, 73, 355, 0, 0, 0, - 0, 86, 0, 0, 82, 85, 77, 0, 0, 74, - 76, 79, 75, 87, 80, 0, 83, 0, 0, 177, - 0, 0, 164, 183, 166, 165, 0, 0, 0, 179, - 180, 178, 182, 0, 212, 0, 0, 0, 0, 202, - 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, - 186, 187, 185, 190, 194, 193, 191, 189, 204, 203, - 205, 0, 220, 0, 216, 0, 0, 158, 145, 157, - 146, 114, 115, 116, 141, 117, 142, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 143, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 144, 0, 0, 156, 252, 159, 0, 160, 0, - 161, 155, 0, 248, 241, 239, 246, 247, 245, 244, - 250, 243, 242, 240, 249, 236, 0, 224, 0, 0, - 228, 0, 0, 232, 0, 0, 158, 150, 0, 149, - 0, 154, 168, 0, 344, 344, 345, 0, 342, 0, - 343, 0, 346, 259, 266, 265, 273, 261, 0, 262, - 0, 347, 0, 354, 263, 264, 81, 269, 267, 351, - 348, 353, 270, 0, 281, 0, 0, 0, 0, 338, - 0, 355, 253, 295, 0, 0, 0, 282, 0, 0, - 271, 272, 0, 260, 268, 296, 297, 0, 344, 0, - 0, 346, 0, 339, 340, 0, 328, 352, 0, 312, - 313, 314, 315, 0, 308, 309, 310, 311, 336, 337, - 0, 0, 0, 0, 0, 300, 301, 302, 257, 255, - 217, 225, 221, 237, 213, 258, 0, 164, 229, 233, - 206, 195, 0, 0, 214, 0, 0, 0, 0, 207, - 0, 0, 0, 0, 0, 199, 197, 200, 198, 196, - 209, 208, 210, 0, 222, 0, 218, 0, 256, 164, - 0, 238, 253, 254, 0, 253, 0, 0, 304, 0, - 0, 0, 306, 0, 226, 0, 0, 230, 0, 0, - 234, 293, 0, 285, 294, 288, 0, 292, 0, 253, - 286, 0, 253, 0, 0, 305, 0, 0, 0, 307, - 0, 0, 0, 299, 0, 298, 81, 108, 356, 0, - 0, 113, 275, 278, 0, 114, 281, 117, 142, 119, - 120, 84, 124, 125, 78, 126, 129, 82, 85, 253, - 79, 87, 132, 80, 134, 83, 136, 137, 282, 139, - 140, 144, 0, 110, 109, 112, 96, 111, 95, 0, - 105, 276, 274, 0, 0, 0, 346, 0, 106, 152, - 153, 158, 0, 151, 0, 316, 317, 0, 344, 0, - 0, 346, 0, 107, 0, 0, 0, 319, 324, 322, - 325, 0, 0, 323, 324, 0, 320, 0, 321, 277, - 327, 0, 277, 326, 0, 329, 330, 0, 277, 331, - 332, 0, 0, 333, 0, 0, 0, 334, 335, 170, - 169, 0, 0, 0, 303, 0, 0, 0, 318, 290, - 283, 0, 291, 287, 0, 289, 279, 0, 280, 284, - 0, 0, 346, 0, 341, 99, 0, 0, 103, 90, - 0, 92, 101, 0, 93, 102, 104, 94, 100, 91, - 0, 97, 174, 172, 176, 173, 171, 175, 349, 6, - 350, 4, 2, 71, 98, 0, 0, 74, 76, 75, - 37, 5, 0, 72, 0, 51, 50, 49, 0, 0, + 0, 0, 28, 0, 0, 0, 28, 0, 185, 252, + 216, 224, 220, 164, 236, 212, 3, 149, 82, 165, + 228, 232, 153, 182, 163, 168, 148, 202, 189, 0, + 89, 90, 85, 0, 79, 74, 356, 0, 0, 0, + 0, 87, 0, 0, 83, 86, 78, 0, 0, 75, + 77, 80, 76, 88, 81, 0, 84, 0, 0, 178, + 0, 0, 165, 184, 167, 166, 0, 0, 0, 180, + 181, 179, 183, 0, 213, 0, 0, 0, 0, 203, + 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, + 187, 188, 186, 191, 195, 194, 192, 190, 205, 204, + 206, 0, 221, 0, 217, 0, 0, 159, 146, 158, + 147, 115, 116, 117, 142, 118, 143, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 144, 132, 133, 134, 135, 136, 137, 138, 139, 140, + 141, 145, 0, 0, 157, 253, 160, 0, 161, 0, + 162, 156, 0, 249, 242, 240, 247, 248, 246, 245, + 251, 244, 243, 241, 250, 237, 0, 225, 0, 0, + 229, 0, 0, 233, 0, 0, 159, 151, 0, 150, + 0, 155, 169, 0, 345, 345, 346, 0, 343, 0, + 344, 0, 347, 260, 267, 266, 274, 262, 0, 263, + 0, 348, 0, 355, 264, 265, 82, 270, 268, 352, + 349, 354, 271, 0, 282, 0, 0, 0, 0, 339, + 0, 356, 254, 296, 0, 0, 0, 283, 0, 0, + 272, 273, 0, 261, 269, 297, 298, 0, 345, 0, + 0, 347, 0, 340, 341, 0, 329, 353, 0, 313, + 314, 315, 316, 0, 309, 310, 311, 312, 337, 338, + 0, 0, 0, 0, 0, 301, 302, 303, 258, 256, + 218, 226, 222, 238, 214, 259, 0, 165, 230, 234, + 207, 196, 0, 0, 215, 0, 0, 0, 0, 208, + 0, 0, 0, 0, 0, 200, 198, 201, 199, 197, + 210, 209, 211, 0, 223, 0, 219, 0, 257, 165, + 0, 239, 254, 255, 0, 254, 0, 0, 305, 0, + 0, 0, 307, 0, 227, 0, 0, 231, 0, 0, + 235, 294, 0, 286, 295, 289, 0, 293, 0, 254, + 287, 0, 254, 0, 0, 306, 0, 0, 0, 308, + 0, 0, 0, 300, 0, 299, 82, 109, 357, 0, + 0, 114, 276, 279, 0, 115, 282, 118, 143, 120, + 121, 85, 125, 126, 79, 127, 130, 83, 86, 254, + 80, 88, 133, 81, 135, 84, 137, 138, 283, 140, + 141, 145, 0, 111, 110, 113, 97, 112, 96, 0, + 106, 277, 275, 0, 0, 0, 347, 0, 107, 153, + 154, 159, 0, 152, 0, 317, 318, 0, 345, 0, + 0, 347, 0, 108, 0, 0, 0, 320, 325, 323, + 326, 0, 0, 324, 325, 0, 321, 0, 322, 278, + 328, 0, 278, 327, 0, 330, 331, 0, 278, 332, + 333, 0, 0, 334, 0, 0, 0, 335, 336, 171, + 170, 0, 0, 0, 304, 0, 0, 0, 319, 291, + 284, 0, 292, 288, 0, 290, 280, 0, 281, 285, + 0, 0, 347, 0, 342, 100, 0, 0, 104, 91, + 0, 93, 102, 0, 94, 103, 105, 95, 101, 92, + 0, 98, 175, 173, 177, 174, 172, 176, 350, 6, + 351, 4, 2, 72, 99, 0, 0, 75, 77, 76, + 37, 5, 0, 73, 0, 51, 50, 49, 0, 0, 64, 0, 65, 41, 42, 43, 44, 46, 47, 68, 45, 0, 51, 0, 0, 0, 0, 0, 60, 0, 61, 0, 0, 32, 0, 0, 69, 33, 0, 36, - 34, 30, 0, 35, 31, 0, 62, 0, 63, 152, - 0, 66, 70, 0, 0, 0, 0, 67, 0, 58, + 34, 30, 0, 35, 31, 0, 62, 0, 63, 153, + 0, 66, 70, 0, 0, 0, 0, 153, 278, 0, + 67, 82, 115, 282, 118, 143, 120, 121, 85, 125, + 126, 127, 130, 83, 86, 254, 88, 133, 81, 135, + 84, 137, 138, 283, 140, 141, 145, 71, 0, 58, 52, 59, 53, 0, 0, 0, 0, 55, 0, 56, - 57, 54, 0, 0, 152, 277, 0, 0, 48, 81, - 114, 281, 117, 142, 119, 120, 84, 124, 125, 126, - 129, 82, 85, 253, 87, 132, 80, 134, 83, 136, - 137, 282, 139, 140, 144, 0, 38, 39, 0, 40, - 8, 0, 0, 9, 0, 11, 0, 10, 0, 1, - 27, 15, 14, 26, 13, 12, 29, 7, 0, 18, - 0, 19, 0, 24, 25, 0, 20, 21, 0, 22, - 23, 16, 17, 357}; + 57, 54, 0, 0, 0, 0, 48, 0, 38, 39, + 0, 40, 8, 0, 0, 9, 0, 11, 0, 10, + 0, 1, 27, 15, 14, 26, 13, 12, 29, 7, + 0, 18, 0, 19, 0, 24, 25, 0, 20, 21, + 0, 22, 23, 16, 17, 358}; const short QQmlJSGrammar::goto_default [] = { - 7, 639, 211, 198, 209, 521, 509, 634, 647, 508, - 633, 637, 635, 643, 22, 640, 638, 636, 18, 520, + 7, 641, 211, 198, 209, 521, 509, 636, 649, 508, + 635, 639, 637, 645, 22, 642, 640, 638, 18, 520, 562, 552, 559, 554, 539, 193, 197, 199, 204, 234, - 212, 231, 543, 583, 582, 203, 233, 26, 487, 486, + 212, 231, 543, 613, 612, 203, 233, 26, 487, 486, 359, 358, 9, 357, 360, 202, 480, 361, 109, 17, 147, 24, 13, 146, 19, 25, 59, 23, 8, 28, 27, 280, 15, 274, 10, 270, 12, 272, 11, 271, @@ -209,295 +209,267 @@ const short QQmlJSGrammar::goto_default [] = { 0}; const short QQmlJSGrammar::action_index [] = { - 239, 1406, 2692, 2692, 2794, 1119, 115, 29, 168, -106, - 26, -23, -60, 225, -106, 306, 33, -106, -106, 732, - -2, 145, 243, 223, -106, -106, -106, 379, 227, 1406, - -106, -106, -106, 539, -106, -106, 2488, 1698, 1406, 1406, - 1406, -106, 1023, 1406, -106, -106, -106, 1406, 1406, -106, - -106, -106, -106, -106, -106, 1406, -106, 1406, 1406, -106, - 1406, 1406, 114, 206, -106, -106, 1406, 1406, 1406, -106, - -106, -106, 211, 1406, 302, 1406, 1406, 1406, 1406, 369, - 1406, 1406, 1406, 1406, 1406, 1406, 226, 1406, 1406, 1406, - 135, 151, 110, 257, 279, 276, 256, 222, 475, 475, - 475, 1406, 7, 1406, 57, 2284, 1406, 1406, -106, -106, + 264, 1225, 2708, 2708, 2606, 938, 94, 104, 119, -106, + 92, 79, 81, 262, -106, 263, 78, -106, -106, 654, + 89, 125, 259, 229, -106, -106, -106, 322, 314, 1225, + -106, -106, -106, 412, -106, -106, 2300, 1713, 1225, 1225, + 1225, -106, 842, 1225, -106, -106, -106, 1225, 1225, -106, + -106, -106, -106, -106, -106, 1225, -106, 1225, 1225, -106, + 1225, 1225, 141, 216, -106, -106, 1225, 1225, 1225, -106, + -106, -106, 209, 1225, 281, 1225, 1225, 1225, 1225, 367, + 1225, 1225, 1225, 1225, 1225, 1225, 219, 1225, 1225, 1225, + 101, 102, 115, 314, 314, 314, 314, 314, 357, 347, + 337, 1225, 71, 1225, 70, 2198, 1225, 1225, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, - -106, -106, 136, 1406, -106, -106, 30, -24, -106, 1406, - -106, -106, 1406, -106, -106, -106, -106, -106, -106, -106, - -106, -106, -106, -106, -106, -106, 1406, 2, 1406, 1406, - 10, 97, 1406, -106, 2284, 1406, 1406, -106, 141, -106, - -45, -106, -106, 4, 457, 386, 89, 79, -106, 448, - -106, 74, 2692, -106, -106, -106, -106, -106, 164, -106, - 460, -106, 85, -106, -106, -106, 96, -106, -106, -106, - 2692, -106, -106, 547, -106, 629, 143, 2794, 62, 54, - 43, 2998, 1406, -106, 51, 1406, 52, -106, 47, 45, - -106, -106, 454, -106, -106, -106, -106, 64, 352, 31, - 61, 2692, 27, -106, -106, 2794, -106, -106, 139, -106, - -106, -106, -106, 126, -106, -106, -106, -106, -106, -106, - -6, 25, 1406, 130, 159, -106, -106, -106, 1600, -106, - 68, 65, 5, -106, 308, 60, 3, 835, 99, 105, - 337, 207, 408, 1406, 317, 1406, 1406, 1406, 1406, 353, - 1406, 1406, 1406, 1406, 1406, 186, 203, 204, 212, 219, - 333, 343, 359, 1406, 20, 1406, 202, 1406, -106, 732, - 1406, -106, 1406, 81, 72, 1406, 77, 2794, -106, 1406, - 149, 2794, -106, 1406, 80, 1406, 1406, 94, 88, 1406, - -106, -8, 128, -25, -106, -106, 1406, -106, 471, 1406, - -106, -53, 1406, -56, 2794, -106, 1406, 134, 2794, -106, - 1406, 138, 2794, -5, 2794, -106, -4, -106, 9, -9, - 37, -106, -106, 2794, -12, 555, 32, 629, 123, 1406, - 2794, 41, 18, 504, 2386, 21, 1023, 49, 46, 1505, - 2386, 42, 16, 44, 1406, 24, -10, 1406, 17, 1406, - -15, -18, 2590, -106, -106, -106, -106, -106, -106, 1406, - -106, -106, -106, -1, -26, -3, 2692, -27, -106, 277, - -106, 1406, -28, -106, 90, -106, -106, 1, 552, -40, - -11, 2692, -29, -106, 1406, 117, 14, -106, 50, -106, - 40, 119, 1406, -106, 11, 35, -106, -54, -106, 2794, - -106, 116, 2794, -106, 267, -106, -106, 121, 2794, -7, - -106, -31, -19, -106, 376, 6, 78, -106, -106, -106, - -106, 1406, 98, 2794, -106, 1406, 106, 2794, -106, 76, - -106, 254, -106, -106, 1406, -106, -106, 552, -106, -106, - 71, 75, 2692, 67, -106, -106, 122, 1992, -106, -106, - 1796, -106, -106, 1894, -106, -106, -106, -106, -106, -106, - 113, -106, -106, -106, -106, -106, -106, -106, -106, -106, - 2692, -106, -106, -106, 111, 22, 929, 152, 39, 48, - -106, -106, 301, -106, 147, -106, -106, -106, 468, 155, - -106, 2182, -106, -106, -106, -106, -106, -106, -106, -106, - -106, 178, -30, 463, 181, -14, 400, 229, -106, -32, - -106, 929, 104, -106, 0, 929, -106, -106, 1311, -106, - -106, -106, 1215, -106, -106, 248, -106, 2182, -106, 392, - 59, -106, -106, 244, 552, 73, 2182, -106, 236, -106, - 237, -106, 70, 15, 368, 214, 355, -106, 103, -106, - -106, -106, 2087, 721, 392, 2896, 1698, 34, -106, 56, - 598, 55, 629, 107, 1406, 2794, 53, 23, 544, 36, - 1023, 58, 66, 1505, 69, 38, 63, 1406, 95, 84, - 1406, 102, 1406, 83, 82, 124, -106, -106, 87, -106, - -106, 929, 813, 91, 929, -106, 271, -106, 86, -106, - -106, 100, 101, -106, -106, -106, -106, -106, 552, -106, - 209, -106, 109, -106, -106, 552, -106, -106, 92, -106, - -106, -106, -106, -106, + -106, -106, 98, 1225, -106, -106, 66, 65, -106, 1225, + -106, -106, 1225, -106, -106, -106, -106, -106, -106, -106, + -106, -106, -106, -106, -106, -106, 1225, 44, 1225, 1225, + 64, 57, 1225, -106, 2198, 1225, 1225, -106, 137, -106, + 49, -106, -106, 93, 344, 474, 95, 86, -106, 390, + -106, 85, 2708, -106, -106, -106, -106, -106, 189, -106, + 474, -106, 80, -106, -106, -106, 83, -106, -106, -106, + 2708, -106, -106, 490, -106, 551, 130, 2606, 46, 51, + 52, 2912, 1225, -106, 63, 1225, 56, -106, 58, 60, + -106, -106, 474, -106, -106, -106, -106, 61, 474, 62, + 67, 2708, 68, -106, -106, 2606, -106, -106, 87, -106, + -106, -106, -106, 110, -106, -106, -106, -106, -106, -106, + -24, 69, 1225, 122, 143, -106, -106, -106, 1419, -106, + 74, 76, 77, -106, 269, 73, 72, 611, 75, 114, + 397, 314, 474, 1225, 287, 1225, 1225, 1225, 1225, 397, + 1225, 1225, 1225, 1225, 1225, 218, 215, 198, 192, 182, + 397, 397, 312, 1225, 55, 1225, 59, 1225, -106, 654, + 1225, -106, 1225, 54, 53, 1225, 50, 2606, -106, 1225, + 124, 2606, -106, 1225, 90, 1225, 1225, 105, 88, 1225, + -106, 84, 157, -27, -106, -106, 1225, -106, 474, 1225, + -106, 82, 1225, 91, 2606, -106, 1225, 120, 2606, -106, + 1225, 103, 2606, -9, 2606, -106, -2, -106, 11, -30, + 17, -106, -106, 2606, -37, 469, 15, 551, 138, 1225, + 2606, 14, -16, 433, 2402, -20, 842, 6, 5, 1324, + 2402, 4, -36, 2, 1225, 7, -18, 1225, 10, 1225, + -26, -13, 2504, -106, -106, -106, -106, -106, -106, 1225, + -106, -106, -106, -33, -59, -25, 2708, 23, -106, 197, + -106, 1225, -12, -106, 140, -106, -106, 22, 474, -4, + 26, 2708, 12, -106, 1225, 113, 30, -106, 142, -106, + 142, 121, 1225, -106, -3, 45, -106, -5, -106, 2606, + -106, 108, 2606, -106, 207, -106, -106, 106, 2606, 37, + -106, 25, 36, -106, 474, 38, 40, -106, -106, -106, + -106, 1225, 136, 2606, -106, 1225, 166, 2606, -106, 13, + -106, 200, -106, -106, 1225, -106, -106, 474, -106, -106, + -17, 16, 2708, -11, -106, -106, 131, 1811, -106, -106, + 1615, -106, -106, 1517, -106, -106, -106, -106, -106, -106, + 109, -106, -106, -106, -106, -106, -106, -106, -106, -106, + 2708, -106, -106, -106, 233, -19, 748, 152, -60, 41, + -106, -106, 191, -106, 177, -106, -106, -106, 387, 203, + -106, 1906, -106, -106, -106, -106, -106, -106, -106, -106, + -106, 180, 43, 376, 174, 48, 474, 240, -106, 8, + -106, 748, 111, -106, -1, 748, -106, -106, 1130, -106, + -106, -106, 1034, -106, -106, 228, -106, 1906, -106, 295, + 21, -106, -106, 184, 379, 39, 2001, 288, 2810, 18, + -106, 34, 482, 33, 551, 138, 1225, 2606, 31, 9, + 399, 3, 643, 19, 29, 1324, 28, 1, 27, 1225, + 24, 0, 1225, 20, 1225, -7, -8, -106, 193, -106, + 205, -106, 47, 42, 329, 208, 319, -106, 128, -106, + -106, -106, 2096, 748, 1713, 35, -106, 132, -106, -106, + 32, -106, -106, 748, 748, 94, 748, -106, 250, -106, + 116, -106, -106, 233, 233, -106, -106, -106, -106, -106, + 393, -106, 214, -106, 100, -106, -106, 474, -106, -106, + 96, -106, -106, -106, -106, -106, - -111, 43, 59, 70, 71, 369, 40, -111, -111, -111, - -111, -111, -111, -111, -111, -111, -111, -111, -111, 21, - -111, -111, -111, -111, -111, -111, -111, -111, -111, 79, - -111, -111, -111, -16, -111, -111, 5, -26, 23, 73, - 91, -111, 83, 61, -111, -111, -111, 88, 87, -111, - -111, -111, -111, -111, -111, 29, -111, 66, 39, -111, - 97, 193, -111, -111, -111, -111, 160, 180, 183, -111, - -111, -111, -111, 176, -111, 167, 151, 155, 152, -111, - 148, 187, 195, 197, 199, 201, -111, 186, 92, 194, + -111, 15, 71, 87, 80, 305, -6, -111, -111, -111, + -111, -111, -111, -111, -111, -111, -111, -111, -111, -42, + -111, -111, -111, -111, -111, -111, -111, -111, -111, 95, + -111, -111, -111, 3, -111, -111, -5, -11, 9, 109, + 91, -111, 62, 45, -111, -111, -111, 50, 63, -111, + -111, -111, -111, -111, -111, 32, -111, 203, 197, -111, + 189, 178, -111, -111, -111, -111, 182, 185, 188, -111, + -111, -111, -111, 193, -111, 198, 168, 113, 114, -111, + 133, 116, 123, 129, 130, 132, -111, 136, 139, 142, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, 103, -111, 108, -111, 181, -2, -42, -111, -111, + -111, 148, -111, 151, -111, 186, 6, -37, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -111, 34, -111, -111, -111, -111, -111, 3, - -111, -111, 10, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -111, -111, -111, -111, 127, -111, 109, 15, - -111, -111, 16, -111, 225, 44, 128, -111, -111, -111, - -111, -111, -111, -111, 25, 157, -111, -111, -111, 26, - -111, -111, 24, -111, -111, -111, -111, -111, -111, -111, - 22, -111, -111, -111, -111, -111, -111, -111, -111, -111, - 179, -111, -111, 45, -111, 46, -111, 107, -111, 48, - -111, 106, 62, -111, -111, 163, -3, -111, -111, -111, - -111, -111, -14, -111, -111, -111, -111, -111, 57, -111, - -111, 224, -111, -111, -111, 227, -111, -111, -111, -111, + -111, -111, -111, 42, -111, -111, -111, -111, -111, 22, + -111, -111, 2, -111, -111, -111, -111, -111, -111, -111, + -111, -111, -111, -111, -111, -111, 96, -111, 66, 21, + -111, -111, 0, -111, 274, 35, 88, -111, -111, -111, + -111, -111, -111, -111, 41, 75, -111, -111, -111, 49, + -111, -111, 48, -111, -111, -111, -111, -111, -111, -111, + 57, -111, -111, -111, -111, -111, -111, -111, -111, -111, + 77, -111, -111, 54, -111, 27, -111, 243, -111, 25, + -111, 160, 36, -111, -111, 169, 40, -111, -111, -111, + -111, -111, 56, -111, -111, -111, -111, -111, 180, -111, + -111, 163, -111, -111, -111, 246, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, 35, -111, -111, -111, -111, -111, 72, -111, + -111, -111, 8, -111, -111, -111, -111, -111, 69, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, 12, 264, -111, 258, 246, 254, 209, -111, - 60, 51, 52, 27, 53, -111, -111, -111, -111, -111, - -111, -111, -111, 244, -111, 255, -111, 203, -111, -111, - 207, -111, 217, -111, -111, 198, -111, 208, -111, 8, - -111, 215, -111, 232, -111, 233, 234, -111, -111, 223, - -111, -111, -111, -111, -111, -111, 230, -111, 95, 113, - -111, -111, 153, -111, 156, -111, 2, -111, 147, -111, - 58, -111, 137, -111, 100, -111, -111, -111, -111, -111, - -111, -111, -111, 135, -111, 41, -111, 54, -111, 117, - 162, -111, -111, 50, 169, -111, 174, -111, -111, 32, - 178, -111, -111, -111, 31, -111, 7, 144, -111, 130, - -111, -111, 142, -111, -111, -111, -111, -111, -111, 11, - -111, -111, -111, -111, -111, -111, 214, -111, -111, -111, - -111, 140, -111, -111, -111, -111, -111, -111, 158, -111, - -111, 149, -111, -111, 47, -111, -111, -111, -111, -111, - -55, -111, 38, -111, -67, -111, -111, -111, -111, 263, - -111, -111, 262, -111, -111, -111, -111, -111, 190, -76, - -111, -111, 30, -111, 19, -111, 14, -111, -111, -111, - -111, 33, -111, 272, -111, 64, -111, 175, -111, -111, - -111, -111, -111, -111, 18, -111, -111, 69, -111, -111, - -111, -111, 114, -111, -111, -111, -111, 20, -111, -111, - 110, -111, -111, 28, -111, -111, -111, -111, -111, -111, + -111, -111, 61, 211, -111, 272, 257, 256, 236, -111, + 81, 83, 85, 68, 94, -111, -111, -111, -111, -111, + -111, -111, -111, 235, -111, 218, -111, 209, -111, -111, + 244, -111, 227, -111, -111, 228, -111, 238, -111, 33, + -111, 167, -111, 245, -111, 253, 254, -111, -111, 225, + -111, -111, -111, -111, -111, -111, 217, -111, 194, 213, + -111, -111, 208, -111, 207, -111, 52, -111, 205, -111, + 55, -111, 201, -111, 199, -111, -111, -111, -111, -111, + -111, -111, -111, 278, -111, 39, -111, 34, -111, 173, + 219, -111, -111, 53, 231, -111, 73, -111, -111, 44, + 59, -111, -111, -111, 47, -111, 24, 102, -111, 101, + -111, -111, 111, -111, -111, -111, -111, -111, -111, 26, + -111, -111, -111, -111, -111, -111, 65, -111, -111, -111, + -111, 76, -111, -111, -111, -111, -111, -111, 79, -111, + -111, 89, -111, -111, 51, -111, -111, -111, -111, -111, + -62, -111, 37, -111, -63, -111, -111, -111, -111, 387, + -111, -111, 264, -111, -111, -111, -111, -111, 158, -54, + -111, -111, 28, -111, 38, -111, 23, -111, -111, -111, + -111, 43, -111, 78, -111, 58, -111, 67, -111, -111, + -111, -111, -111, -111, 18, -111, -111, 195, -111, -111, + -111, -111, 161, -111, -111, -111, -111, 20, -111, -111, + 157, -111, -111, 31, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - 86, -111, -111, -111, -111, -111, 55, -111, -111, -111, - -111, -111, -111, -111, -7, -111, -111, -111, 1, -111, - -111, 329, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -111, 0, -11, -111, -10, -111, -111, -111, - -111, 204, -111, -111, -111, 205, -111, -111, 317, -111, - -111, -111, 311, -111, -111, -111, -111, 370, -111, -111, - -9, -111, -111, -4, -12, -111, 337, -111, -111, -111, - -18, -111, -111, -111, -1, -17, -6, -111, -111, -111, - -111, -111, 466, 78, -111, 82, 307, -13, -111, -111, - -8, -111, 6, -111, 74, 76, -111, -111, 9, -111, - 85, -111, -111, 17, -111, -111, -111, 4, -111, -22, - 84, -111, 67, -111, -111, -111, -111, -111, 49, -111, - -111, 37, 42, 68, 77, -111, -111, -111, -111, -111, - -111, -111, -111, -111, -111, -111, -111, -111, 13, -111, - -111, -111, -111, -111, -111, 36, -111, -111, -111, -111, - -111, -111, -111, -111}; + 206, -111, -111, -111, -111, -111, -7, -111, -111, -111, + -111, -111, -111, -111, -24, -111, -111, -111, -12, -111, + -111, 342, -111, -111, -111, -111, -111, -111, -111, -111, + -111, -111, -111, -16, -32, -111, 5, -111, -111, -111, + -111, 152, -111, -111, -111, 248, -111, -111, 330, -111, + -111, -111, 324, -111, -111, -111, -111, 385, -111, -111, + -21, -111, -111, 1, 14, -111, 367, -111, 232, 12, + -111, -111, 11, -111, 10, -111, 164, 141, -111, -111, + 7, -111, 64, -111, -111, 19, -111, -111, -111, 17, + -111, -1, 60, -111, 46, -111, -111, -111, -111, -111, + -15, -111, -111, -111, -2, -17, -4, -111, -111, -111, + -111, -111, 484, 138, 313, -3, -111, -111, -111, -111, + 4, -111, -111, 13, 16, 97, 127, -111, -111, -111, + -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, + -14, -111, -111, -111, -111, -111, -111, -8, -111, -111, + -111, -111, -111, -111, -111, -111}; const short QQmlJSGrammar::action_info [] = { - 166, 438, 551, 245, 344, 454, 346, 544, 342, 336, - 546, 354, 166, 452, 448, 181, 432, 392, 465, 103, - 420, 461, 421, 448, -138, 101, 423, 73, 408, 663, - 406, -135, 413, 558, 405, 404, 151, 418, 149, -141, - 185, 143, 439, 402, 399, 432, 398, 428, -122, -111, - 101, -133, 424, -112, 268, 432, -130, 350, 73, 268, - -122, 262, -141, 245, 312, -130, 456, 558, 307, 283, - -133, 261, 350, -112, 424, 588, -111, 578, 585, 350, - 576, 465, 243, 461, 305, 448, 103, 424, 524, 143, - 184, 240, 558, 474, 241, 329, 323, 189, 268, 305, - 238, 323, -135, 245, 172, 573, 143, 192, 482, -138, - 0, 448, 555, 303, 143, 174, 174, 448, 465, 461, - 558, 143, 484, 442, 143, 143, 174, 451, 303, 435, - 490, 481, 555, 315, 175, 175, 338, 317, 143, 191, - 244, 452, 143, 0, 143, 175, 143, 662, 661, 143, - 60, 416, 415, 660, 659, 325, 64, 143, 463, 326, - 556, 61, 531, 0, 590, 589, 467, 65, 259, 258, - 654, 653, 143, 501, 436, 60, 525, 426, 491, 0, - 626, 542, 631, 632, 259, 258, 61, 257, 256, 339, - 264, 60, 144, 174, 348, 168, 0, 179, 352, 169, - 252, 251, 61, 283, 259, 258, 631, 632, 60, 321, - 525, 87, 175, 88, 411, 0, 532, 530, 66, 61, - 267, 265, 527, 66, 89, 236, 235, 527, 87, 87, - 88, 88, 87, 526, 88, 66, 549, 87, 526, 88, - 105, 89, 89, 525, 87, 89, 88, 87, 266, 88, - 89, 87, 87, 88, 88, 567, 527, 89, 174, 106, - 89, 107, 477, 67, 89, 89, 525, 526, 67, 68, - 657, 656, 580, 525, 68, 143, 0, 175, 0, 176, - 67, 87, 87, 88, 88, 0, 68, 0, 0, 527, - 550, 548, 174, 0, 89, 89, 0, 581, 579, 0, - 526, 87, 655, 88, 87, 0, 88, 0, 592, 568, - 566, 175, 527, 411, 89, 478, 476, 89, 650, 527, - 75, 76, 0, 526, 75, 76, 285, 286, 446, 445, - 526, 0, 651, 649, 558, 285, 286, 6, 5, 4, - 1, 3, 2, 0, 0, 0, 0, 77, 78, 0, - 0, 77, 78, 287, 288, 0, 290, 291, 0, 0, - 290, 291, 287, 288, 648, 292, 290, 291, 293, 292, - 294, 0, 293, 0, 294, 292, 290, 291, 293, 0, - 294, 35, 290, 291, 35, 292, 0, 0, 293, 0, - 294, 292, 80, 81, 293, 593, 294, 35, 0, 0, - 82, 83, 80, 81, 84, 35, 85, 174, 0, 0, - 82, 83, 0, 0, 84, 35, 85, 0, 49, 52, - 50, 49, 52, 50, 0, -98, 175, 0, 176, 35, - 0, 0, 0, 0, 49, 52, 50, 35, 0, 0, - 0, 0, 49, 52, 50, 0, 46, 34, 51, 46, - 34, 51, 49, 52, 50, 0, 0, 0, 0, 0, - 0, 0, 46, 34, 51, 0, 49, 52, 50, 0, - 46, 34, 51, 0, 49, 52, 50, 35, 0, 0, - 46, 34, 51, 35, 0, 0, 35, 0, 0, 35, - 0, 0, 35, 0, 46, 34, 51, 35, 80, 81, - 35, 0, 46, 34, 51, 0, 82, 83, 0, 0, - 84, 0, 85, 0, 49, 52, 50, 0, 0, 0, - 49, 52, 50, 49, 52, 50, 49, 52, 50, 49, - 52, 50, 0, 35, 49, 52, 50, 49, 52, 50, - 184, 0, 46, 34, 51, 0, 0, 0, 46, 34, - 51, 46, 34, 51, 46, 34, 51, 46, 34, 51, - 0, 0, 46, 34, 51, 46, 34, 51, 35, 0, - 49, 52, 50, 35, 0, 184, 35, 0, 0, 0, - 184, 35, 0, 0, 35, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 46, 34, - 51, 0, 0, 0, 0, 49, 52, 50, 250, 249, - 49, 52, 50, 49, 52, 50, 250, 249, 49, 52, - 50, 49, 52, 50, 0, 0, 0, 35, 0, 0, + 424, 405, 432, 404, 346, 245, 573, 354, 406, -134, + 461, -112, -113, -131, -136, 448, 350, -139, 402, 392, + 268, -123, -142, 465, 399, 398, -131, -139, 465, 461, + 474, -136, 558, 448, -134, -112, -113, 424, -123, 350, + -142, 245, 551, 481, 484, 268, 576, 524, 413, 482, + 438, 558, 439, 261, 558, 615, 420, 452, 418, 421, + 283, 454, 143, 428, 172, 558, 166, 423, 558, 448, + 608, 73, 546, 448, 149, 283, 0, 323, 408, 0, + 544, 307, 268, 0, 0, 0, 143, 184, 350, 448, + 245, 166, 101, 73, 461, 329, 465, 238, 456, 424, + 241, 336, 618, 189, 665, 262, 143, 323, 0, 181, + 317, 143, 451, 0, 315, 442, 143, 143, 192, 555, + 0, 143, 240, 243, 303, 151, 452, 101, 143, 185, + 143, 435, 143, 312, 305, 244, 0, 0, 303, 490, + 555, 60, 60, 342, 143, 143, 191, 432, 252, 251, + 103, 344, 61, 61, 144, 60, 305, 662, 661, 60, + 103, 656, 655, 352, 325, 338, 61, 556, 326, 501, + 61, 257, 256, 426, 143, 168, 436, 664, 663, 169, + 348, 542, 264, 64, 321, 633, 634, 491, 628, 620, + 619, 259, 258, 179, 65, 174, 463, 143, 622, 259, + 258, 416, 415, 525, 267, 265, 525, 87, 477, 88, + 531, 0, 174, 525, 175, 143, 411, 87, 339, 88, + 89, 66, 0, 87, 558, 88, 467, 527, 66, 610, + 89, 175, 266, 411, 525, 567, 89, 525, 526, 0, + 87, 66, 88, 87, 87, 88, 88, 549, 174, 527, + 236, 235, 527, 89, 611, 609, 89, 89, 0, 527, + 526, 478, 476, 526, 532, 530, 67, 175, 446, 445, + 526, 0, 68, 67, 174, 659, 658, 105, 0, 68, + 527, 75, 76, 527, 0, 623, 67, 285, 286, 568, + 566, 526, 68, 175, 526, 176, 106, 652, 107, 75, + 76, 550, 548, 174, 0, 285, 286, 657, 77, 78, + 174, 653, 651, 0, 287, 288, 0, 0, 0, 0, + 0, -99, 175, 0, 176, 0, 77, 78, -99, 175, + 0, 176, 287, 288, 0, 290, 291, 0, 0, 87, + 0, 88, 0, 650, 292, 80, 81, 293, 35, 294, + 0, 0, 89, 82, 83, 0, 0, 84, 35, 85, + 80, 81, 6, 5, 4, 1, 3, 2, 82, 83, + 80, 81, 84, 35, 85, 0, 0, 0, 82, 83, + 80, 81, 84, 0, 85, 49, 52, 50, 82, 83, + 80, 81, 84, 0, 85, 49, 52, 50, 82, 83, + 0, 0, 84, 0, 85, 35, 0, 0, 35, 0, + 49, 52, 50, 46, 34, 51, 35, 0, 0, 35, + 290, 291, 35, 46, 34, 51, 0, 0, 35, 292, + 0, 0, 293, 0, 294, 184, 0, 0, 46, 34, + 51, 35, 49, 52, 50, 49, 52, 50, 184, 0, + 0, 0, 0, 49, 52, 50, 49, 52, 50, 49, + 52, 50, 35, 0, 0, 49, 52, 50, 0, 184, + 46, 34, 51, 46, 34, 51, 0, 0, 49, 52, + 50, 46, 34, 51, 46, 34, 51, 46, 34, 51, + 0, 0, 0, 46, 34, 51, 0, 0, 35, 49, + 52, 50, 0, 35, 0, 0, 46, 34, 51, 0, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 35, + 0, 0, 0, 0, 0, 0, 0, 46, 34, 51, + 250, 249, 0, 0, 0, 49, 52, 50, 0, 0, + 49, 52, 50, 250, 249, 0, 0, 0, 49, 52, + 50, 250, 249, 0, 0, 0, 49, 52, 50, 0, 0, 0, 0, 46, 34, 51, 0, 0, 46, 34, - 51, 46, 34, 51, 0, 0, 46, 34, 51, 46, - 34, 51, 0, 0, 0, 0, 0, 0, 35, 250, - 249, 0, 0, 0, 49, 52, 50, 0, 0, 0, + 51, 0, 0, 0, 0, 0, 46, 34, 51, 0, + 35, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 255, 254, 46, 34, 51, 49, 52, 50, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, - 0, 0, 0, 30, 31, 153, 0, 0, 0, 0, - 0, 0, 0, 33, 0, 154, 0, 0, 0, 155, - 35, 0, 0, 0, 36, 37, 0, 38, 156, 0, - 157, 0, 0, 0, 516, 0, 0, 0, 45, 0, - 0, 158, 0, 159, 64, 0, 0, 0, 0, 0, - 0, 160, 0, 0, 161, 65, 53, 49, 52, 50, - 162, 54, 0, 0, 0, 0, 163, 0, 0, 0, - 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, - 0, 0, 164, 0, 0, 46, 34, 51, 0, 0, - 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, - 0, 0, 0, 0, 0, 33, 0, 0, 153, 0, - 0, 0, 35, 0, 0, 0, 36, 37, 154, 38, - 0, 0, 155, 0, 0, 0, 516, 0, 0, 0, - 45, 156, 0, 157, 0, 0, 319, 0, 0, 0, - 0, 0, 0, 0, 158, 0, 159, 64, 53, 49, - 52, 50, 0, 54, 160, 0, 0, 161, 65, 0, - 0, 0, 0, 162, 44, 56, 32, 0, 0, 163, - 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, - 0, 0, 0, 0, 0, 164, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, - 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 36, 37, 0, 38, 0, 0, 0, 0, - 0, 0, 516, 0, 0, 0, 45, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, - 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, - 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, - 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, - 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, - 52, 50, 0, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 255, 254, 153, 0, 0, 49, 52, 50, + 0, 0, 0, 0, 154, 0, 0, 0, 155, 0, + 0, 0, 0, 0, 0, 0, 0, 156, 0, 157, + 0, 0, 319, 0, 0, 46, 34, 51, 0, 0, + 158, 0, 159, 64, 0, 30, 31, 153, 0, 0, + 160, 0, 0, 161, 65, 33, 0, 154, 0, 162, + 0, 155, 35, 0, 0, 163, 36, 37, 0, 38, + 156, 0, 157, 0, 0, 0, 42, 0, 0, 0, + 45, 164, 0, 158, 0, 159, 64, 0, 0, 0, + 0, 0, 0, 160, 0, 0, 161, 65, 53, 49, + 52, 50, 162, 54, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, - 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 515, - 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, - 0, 219, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 36, 37, 0, 38, 0, 0, 0, 0, - 0, 0, 516, 0, 0, 0, 45, 0, 0, 0, + 41, 0, 0, 0, 164, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 53, 517, 519, 518, 0, 54, - 0, 0, 0, 0, 227, 0, 0, 0, 0, 0, - 44, 56, 32, 214, 0, 0, 41, 0, 0, 0, - 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 515, 0, 30, 31, 0, - 0, 0, 0, 0, 0, 0, 0, 219, 0, 0, - 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, - 0, 38, 0, 0, 0, 0, 0, 0, 516, 0, - 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, - 563, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 53, 517, 519, 518, 0, 54, 0, 0, 0, 0, - 227, 0, 0, 0, 0, 0, 44, 56, 32, 214, - 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, - 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 515, 0, 30, 31, 0, 0, 0, 0, 0, - 0, 0, 0, 219, 0, 0, 0, 0, 0, 0, - 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, - 0, 0, 0, 0, 516, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 517, 519, 518, - 0, 54, 0, 0, 0, 0, 227, 0, 0, 0, - 0, 0, 44, 56, 32, 214, 0, 0, 41, 0, - 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, - 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, - 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, - 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, - 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, - 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, - 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, - 0, 0, -131, 0, 0, 0, 29, 30, 31, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, + 0, 36, 37, 0, 38, 0, 0, 0, 0, 0, + 0, 516, 0, 0, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, + 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, + 0, 0, 0, 0, 0, 42, 0, 0, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, + 50, 0, 54, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, + 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 515, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 219, 0, 0, 0, 0, 0, 0, 35, 0, 0, + 0, 36, 37, 0, 38, 0, 0, 0, 0, 0, + 0, 516, 0, 0, 0, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 517, 519, 518, 0, 54, 0, + 0, 0, 0, 227, 0, 0, 0, 0, 0, 44, + 56, 32, 214, 0, 0, 41, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 515, 0, 30, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 219, 0, 0, 0, + 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, + 38, 0, 0, 0, 0, 0, 0, 516, 0, 0, + 0, 45, 0, 0, 0, 0, 0, 0, 0, 563, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, + 517, 519, 518, 0, 54, 0, 0, 0, 0, 227, + 0, 0, 0, 0, 0, 44, 56, 32, 214, 0, + 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 515, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 219, 0, 0, 0, 0, 0, 0, 35, + 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, + 0, 0, 0, 516, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 53, 517, 519, 518, 0, + 54, 0, 0, 0, 0, 227, 0, 0, 0, 0, + 0, 44, 56, 32, 214, 0, 0, 41, 0, 0, + 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, @@ -507,198 +479,228 @@ const short QQmlJSGrammar::action_info [] = { 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, - 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, - 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, - 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, - 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 49, 52, 50, 0, - 54, 0, 55, 0, 57, 282, 58, 0, 0, 0, - 0, 44, 56, 32, 0, 0, 0, 41, 0, 0, - 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 488, 0, 0, 29, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, - 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, - 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, - 0, 48, 0, 0, 489, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, - 55, 0, 57, 0, 58, 0, 0, 0, 0, 44, - 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, - 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 488, 0, 0, 29, 30, 31, - 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, - 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, - 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, - 0, 0, 494, 0, 0, 0, 0, 0, 0, 0, - 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, - 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, - 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, - 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 496, 0, 0, 29, 30, 31, 0, 0, + 0, -132, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, 0, 0, - 497, 0, 0, 0, 0, 0, 0, 0, 0, 53, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 496, 0, 0, 29, 30, 31, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, - 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, - 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, - 0, 0, 0, 47, 0, 48, 0, 0, 499, 0, - 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, - 50, 0, 54, 0, 55, 0, 57, 0, 58, 0, - 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, - 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, + 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, + 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, + 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, + 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, + 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, + 0, 55, 0, 57, 282, 58, 0, 0, 0, 0, + 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, + 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 496, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, - 0, 0, 0, 0, 0, 0, 35, 220, 0, 0, - 595, 596, 0, 38, 0, 0, 0, 39, 0, 40, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 36, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, - 48, 0, 0, 0, 0, 0, 0, 0, 223, 0, - 0, 0, 53, 49, 52, 50, 224, 54, 0, 55, - 226, 57, 0, 58, 0, 229, 0, 0, 44, 56, + 48, 0, 0, 497, 0, 0, 0, 0, 0, 0, + 0, 0, 53, 49, 52, 50, 0, 54, 0, 55, + 0, 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, - 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, - 0, 35, 220, 0, 0, 221, 37, 0, 38, 0, - 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, - 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, - 0, 0, 0, 223, 0, 0, 0, 53, 49, 52, - 50, 224, 54, 0, 55, 226, 57, 0, 58, 0, - 229, 0, 0, 44, 56, 32, 0, 0, 0, 41, + 0, 0, 0, 488, 0, 0, 29, 30, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, + 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, + 0, 0, 45, 0, 0, 0, 47, 0, 48, 0, + 0, 494, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 49, 52, 50, 0, 54, 0, 55, 0, 57, + 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, + 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 488, 0, 0, 29, 30, 31, 0, 0, 0, + 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, + 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, + 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, + 45, 0, 0, 0, 47, 0, 48, 0, 0, 489, + 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, + 52, 50, 0, 54, 0, 55, 0, 57, 0, 58, + 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, + 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 496, + 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, + 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, + 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, + 0, 0, 47, 0, 48, 0, 0, 499, 0, 0, + 0, 0, 0, 0, 0, 0, 53, 49, 52, 50, + 0, 54, 0, 55, 0, 57, 0, 58, 0, 0, + 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, + 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 0, 0, 0, 35, 220, 0, 0, 221, + 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, + 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, + 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, + 0, 53, 49, 52, 50, 224, 54, 0, 55, 226, + 57, 0, 58, 0, 229, 0, 0, 44, 56, 32, + 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, + 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, + 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, + 35, 220, 0, 0, 578, 37, 0, 38, 0, 0, + 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, + 0, 0, 47, 0, 48, 0, 0, 0, 0, 0, + 0, 0, 223, 0, 0, 0, 53, 49, 52, 50, + 224, 54, 0, 55, 226, 57, 0, 58, 0, 229, + 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, + 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 0, 0, 0, 35, 220, 0, 0, 578, + 624, 0, 38, 0, 0, 0, 39, 0, 40, 42, + 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, + 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, + 0, 53, 49, 52, 50, 224, 54, 0, 55, 226, + 57, 0, 58, 0, 229, 0, 0, 44, 56, 32, + 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, + 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 111, 112, 113, 0, 0, 115, 117, 118, + 0, 0, 119, 0, 120, 0, 0, 0, 122, 123, + 124, 0, 0, 0, 0, 0, 0, 35, 125, 126, + 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, + 0, 0, 0, 0, 49, 52, 50, 132, 133, 134, + 0, 136, 137, 138, 139, 140, 141, 0, 0, 129, + 135, 121, 114, 116, 130, 0, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, + 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, + 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, + 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 128, 0, 0, 0, 395, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, + 0, 0, 0, 0, 0, 397, 49, 52, 50, 132, + 133, 134, 0, 136, 137, 138, 139, 140, 141, 0, + 0, 129, 135, 121, 114, 116, 130, 0, 0, 0, + 0, 0, 0, 0, 46, 374, 380, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 111, 112, 113, 0, + 0, 115, 117, 118, 0, 0, 119, 0, 120, 0, + 0, 0, 122, 123, 124, 0, 0, 0, 0, 0, + 0, 35, 125, 126, 127, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 0, 0, 0, 395, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 131, 0, 0, 0, 0, 0, 397, 49, 52, + 50, 132, 133, 134, 0, 136, 137, 138, 139, 140, + 141, 0, 0, 129, 135, 121, 114, 116, 130, 0, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, + 0, 395, 0, 0, 0, 0, 0, 0, 0, 396, + 0, 0, 0, 131, 0, 0, 0, 0, 0, 397, 49, 52, 50, 132, 133, 134, 0, 136, 137, 138, 139, 140, 141, 0, 0, 129, 135, 121, 114, 116, - 130, 0, 0, 0, 0, 0, 0, 0, 46, 34, - 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 111, 112, 113, 0, 0, 115, 117, 118, 0, 0, - 119, 0, 120, 0, 0, 0, 122, 123, 124, 0, - 0, 0, 0, 0, 0, 35, 125, 126, 127, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, - 0, 0, 0, 395, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, - 0, 397, 49, 52, 50, 132, 133, 134, 0, 136, - 137, 138, 139, 140, 141, 0, 0, 129, 135, 121, - 114, 116, 130, 0, 0, 0, 0, 0, 0, 0, + 130, 0, 0, 0, 0, 0, 0, 0, 46, 374, + 380, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 213, 0, 0, 0, 0, 215, 0, 29, 30, 31, + 217, 0, 0, 0, 0, 0, 0, 218, 33, 0, + 0, 0, 0, 0, 0, 35, 220, 0, 0, 221, + 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, + 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, + 0, 0, 0, 0, 0, 222, 0, 223, 0, 0, + 0, 53, 49, 52, 50, 224, 54, 225, 55, 226, + 57, 227, 58, 228, 229, 0, 0, 44, 56, 32, + 214, 216, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 111, 112, 113, 0, 0, 115, 117, 118, - 0, 0, 119, 0, 120, 0, 0, 0, 122, 123, - 124, 0, 0, 0, 0, 0, 0, 35, 125, 126, - 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 128, 0, 0, 0, 395, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, - 0, 0, 0, 397, 49, 52, 50, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 141, 0, 0, 129, - 135, 121, 114, 116, 130, 0, 0, 0, 0, 0, - 0, 0, 46, 374, 380, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, - 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, - 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, - 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 128, 0, 0, 0, 395, 0, 0, - 0, 0, 0, 0, 0, 396, 0, 0, 0, 131, - 0, 0, 0, 0, 0, 397, 49, 52, 50, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 141, 0, - 0, 129, 135, 121, 114, 116, 130, 0, 0, 0, + 0, 0, 213, 0, 0, 0, 0, 215, 0, 29, + 30, 31, 217, 0, 0, 0, 0, 0, 0, 218, + 219, 0, 0, 0, 0, 0, 0, 35, 220, 0, + 0, 221, 37, 0, 38, 0, 0, 0, 39, 0, + 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, + 0, 48, 0, 0, 0, 0, 0, 222, 0, 223, + 0, 0, 0, 53, 49, 52, 50, 224, 54, 225, + 55, 226, 57, 227, 58, 228, 229, 0, 0, 44, + 56, 32, 214, 216, 0, 41, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 582, 112, 113, 0, 0, 584, + 117, 586, 30, 31, 587, 0, 120, 0, 0, 0, + 122, 589, 590, 0, 0, 0, 0, 0, 0, 35, + 591, 126, 127, 221, 37, 0, 38, 0, 0, 0, + 39, 0, 40, 592, 43, 0, 0, 594, 0, 0, + 0, 47, 0, 48, 0, 0, 0, 0, 0, 595, + 0, 223, 0, 0, 0, 596, 49, 52, 50, 597, + 598, 599, 55, 601, 602, 603, 604, 605, 606, 0, + 0, 593, 600, 588, 583, 585, 130, 41, 0, 0, 0, 0, 0, 0, 46, 374, 380, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, - 0, 215, 0, 29, 30, 31, 217, 0, 0, 0, - 0, 0, 0, 218, 219, 0, 0, 0, 0, 0, - 0, 35, 220, 0, 0, 221, 37, 0, 38, 0, - 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, - 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, - 0, 222, 0, 223, 0, 0, 0, 53, 49, 52, - 50, 224, 54, 225, 55, 226, 57, 227, 58, 228, - 229, 0, 0, 44, 56, 32, 214, 216, 0, 41, - 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 213, 0, - 0, 0, 0, 215, 0, 29, 30, 31, 217, 0, - 0, 0, 0, 0, 0, 218, 33, 0, 0, 0, - 0, 0, 0, 35, 220, 0, 0, 221, 37, 0, - 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, - 0, 45, 0, 0, 0, 47, 0, 48, 0, 0, - 0, 0, 0, 222, 0, 223, 0, 0, 0, 53, - 49, 52, 50, 224, 54, 225, 55, 226, 57, 227, - 58, 228, 229, 0, 0, 44, 56, 32, 214, 216, - 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, - 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 600, 112, 113, 0, 0, 602, 117, 604, 30, 31, - 605, 0, 120, 0, 0, 0, 122, 607, 608, 0, - 0, 0, 0, 0, 0, 35, 609, 126, 127, 221, - 37, 0, 38, 0, 0, 0, 39, 0, 40, 610, - 43, 0, 0, 612, 0, 0, 0, 47, 0, 48, - 0, 0, 0, 0, 0, 613, 0, 223, 0, 0, - 0, 614, 49, 52, 50, 615, 616, 617, 55, 619, - 620, 621, 622, 623, 624, 0, 0, 611, 618, 606, - 601, 603, 130, 41, 0, 0, 0, 0, 0, 0, - 46, 374, 380, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 365, 112, 113, 0, 0, 367, 117, 369, - 30, 31, 370, 0, 120, 0, 0, 0, 122, 372, - 373, 0, 0, 0, 0, 0, 0, 35, 375, 126, - 127, 221, 37, 0, 38, 0, 0, 0, 39, 0, - 40, 376, 43, 0, 0, 378, 0, 0, 0, 47, - 0, 48, 0, -277, 0, 0, 0, 379, 0, 223, - 0, 0, 0, 381, 49, 52, 50, 382, 383, 384, - 55, 386, 387, 388, 389, 390, 391, 0, 0, 377, - 385, 371, 366, 368, 130, 41, 0, 0, 0, 0, - 0, 0, 46, 374, 380, 0, 0, 0, 0, 0, - 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 112, 113, 0, + 0, 367, 117, 369, 30, 31, 370, 0, 120, 0, + 0, 0, 122, 372, 373, 0, 0, 0, 0, 0, + 0, 35, 375, 126, 127, 221, 37, 0, 38, 0, + 0, 0, 39, 0, 40, 376, 43, 0, 0, 378, + 0, 0, 0, 47, 0, 48, 0, -278, 0, 0, + 0, 379, 0, 223, 0, 0, 0, 381, 49, 52, + 50, 382, 383, 384, 55, 386, 387, 388, 389, 390, + 391, 0, 0, 377, 385, 371, 366, 368, 130, 41, + 0, 0, 0, 0, 0, 0, 46, 374, 380, 0, + 0, 0, 0, 0, 0, 0, 0, 0, - 148, 142, 183, 447, 469, 347, 575, 444, 547, 627, - 248, 320, 587, 572, 584, 586, 485, 591, 565, 529, - 313, 545, 447, 393, 253, 528, 500, 183, 574, 453, - 331, 652, 447, 437, 444, 313, 462, 455, 263, 457, - 237, 441, 206, 188, 190, 150, 16, 178, 433, 630, - 425, 641, 165, 400, 658, 458, 642, 171, 173, 248, - 475, 351, 498, 248, 253, 313, 183, 466, 183, 541, - 495, 629, 253, 512, 511, 188, 145, 206, 260, 645, - 644, 62, 0, 62, 362, 507, 298, 469, 206, 206, - 247, 514, 514, 62, 206, 460, 646, 409, 152, 409, - 599, 628, 355, 239, 206, 62, 62, 62, 362, 260, - 296, 297, 299, 331, 62, 62, 313, 504, 206, 295, - 62, 62, 459, 460, 356, 206, 277, 62, 62, 502, - 182, 281, 206, 62, 410, 182, 410, 401, 62, 353, - 459, 62, 62, 506, 505, 62, 62, 503, 493, 349, - 91, 62, 492, 206, 63, 206, 313, 62, 345, 483, - 393, 479, 62, 62, 260, 206, 444, 206, 510, 102, - 148, 62, 104, 182, 206, 188, 188, 468, 180, 170, - 206, 62, 148, 247, 62, 394, 460, 393, 409, 340, - 412, 341, 362, 206, 422, 167, 393, 206, 62, 108, - 459, 313, 62, 187, 419, 62, 62, 86, 206, 62, - 318, 98, 100, 403, 62, 99, 69, 322, 514, 514, - 313, 62, 417, 553, 557, 410, 206, 79, 110, 246, - 62, 343, 206, 206, 62, 0, 70, 62, 74, 71, - 62, 62, 206, 108, 90, 206, 93, 62, 62, 62, - 72, 62, 92, 62, 94, 62, 95, 309, 96, 407, - 97, 309, 281, 62, 362, 362, 281, 0, 281, 242, - 302, 0, 110, 177, 464, 0, 316, 309, 0, 308, - 206, 206, 281, 311, 309, 0, 62, 62, 309, 281, - 206, 281, 281, 281, 0, 314, 0, 0, 62, 330, - 62, 324, 0, 281, 327, 281, 337, 300, 62, 62, - 328, 304, 62, 281, 281, 301, 564, 281, 62, 289, - 306, 569, 561, 281, 0, 514, 553, 284, 625, 0, - 0, 514, 0, 0, 522, 0, 0, 0, 0, 0, - 522, 0, 0, 0, 0, 0, 513, 523, 0, 485, - 443, 440, 513, 523, 533, 534, 535, 536, 540, 537, - 538, 577, 533, 534, 535, 536, 540, 537, 538, 0, + 545, 572, 565, 632, 654, 148, 529, 541, 528, 142, + 660, 263, 500, 393, 617, 616, 621, 614, 16, 629, + 444, 183, 313, 547, 447, 183, 631, 643, 253, 248, + 644, 485, 575, 574, 607, 152, 320, 437, 178, 313, + 441, 433, 173, 183, 165, 253, 462, 313, 457, 447, + 444, 453, 253, 458, 425, 347, 455, 248, 351, 188, + 475, 466, 498, 171, 150, 447, 206, 190, 400, 468, + 0, 183, 248, 495, 469, 237, 409, 393, 409, 331, + 464, 247, 512, 206, 145, 206, 62, 409, 507, 206, + 0, 511, 0, 188, 0, 206, 206, 188, 206, 62, + 62, 504, 460, 417, 62, 206, 505, 206, 647, 646, + 407, 0, 0, 410, 62, 410, 459, 62, 148, 506, + 62, 187, 62, 277, 410, 419, 412, 298, 281, 393, + 148, 0, 0, 0, 422, 62, 170, 62, 180, 62, + 295, 514, 296, 260, 297, 62, 648, 503, 62, 62, + 62, 182, 514, 299, 394, 62, 62, 460, 459, 206, + 362, 630, 362, 62, 167, 502, 514, 62, 62, 322, + 62, 553, 444, 99, 100, 93, 206, 62, 356, 206, + 510, 206, 94, 62, 62, 206, 62, 62, 95, 96, + 62, 97, 86, 62, 90, 493, 62, 91, 188, 492, + 92, 355, 62, 353, 108, 62, 483, 349, 242, 345, + 247, 313, 331, 469, 102, 104, 313, 206, 62, 206, + 182, 260, 62, 206, 206, 206, 239, 62, 98, 182, + 313, 313, 62, 110, 362, 72, 62, 206, 69, 62, + 318, 70, 62, 62, 71, 260, 63, 62, 246, 393, + 581, 62, 62, 460, 0, 74, 206, 62, 79, 459, + 0, 206, 514, 309, 206, 62, 362, 557, 281, 0, + 281, 309, 62, 0, 284, 403, 281, 281, 0, 309, + 401, 0, 206, 306, 281, 308, 343, 479, 340, 62, + 62, 341, 108, 337, 281, 281, 206, 302, 309, 62, + 0, 330, 304, 281, 281, 314, 316, 62, 309, 0, + 62, 62, 281, 281, 324, 281, 281, 301, 300, 514, + 311, 110, 177, 0, 327, 0, 62, 569, 522, 564, + 328, 281, 553, 289, 627, 561, 0, 0, 514, 0, + 513, 523, 0, 0, 514, 0, 0, 522, 0, 0, + 0, 0, 443, 522, 0, 485, 0, 0, 0, 513, + 523, 0, 0, 0, 0, 513, 523, 533, 534, 535, + 536, 540, 537, 538, 0, 0, 0, 0, 0, 0, + 0, 577, 0, 0, 0, 0, 0, 0, 0, 362, + 579, 580, 533, 534, 535, 536, 540, 537, 538, 569, + 0, 0, 0, 0, 0, 206, 0, 0, 570, 571, + 533, 534, 535, 536, 540, 537, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 514, 569, 0, 0, 0, 0, 0, - 0, 0, 522, 570, 571, 533, 534, 535, 536, 540, - 537, 538, 0, 0, 513, 523, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 440, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 577, 0, + 0, 0, 0, 0, 0, 0, 0, 625, 626, 533, + 534, 535, 536, 540, 537, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -706,170 +708,133 @@ const short QQmlJSGrammar::action_info [] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 594, 0, 0, 0, 0, 0, 0, 0, 0, 597, - 598, 533, 534, 535, 536, 540, 537, 538, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0, 0}; const short QQmlJSGrammar::action_check [] = { - 2, 55, 34, 7, 60, 36, 31, 37, 61, 17, - 24, 16, 2, 20, 33, 60, 5, 8, 36, 79, - 60, 36, 33, 33, 7, 48, 55, 1, 55, 0, - 33, 7, 60, 33, 60, 36, 60, 36, 8, 7, - 36, 8, 7, 55, 7, 5, 55, 33, 7, 7, - 48, 7, 36, 7, 36, 5, 7, 36, 1, 36, - 7, 36, 7, 7, 61, 7, 60, 33, 8, 1, - 7, 77, 36, 7, 36, 60, 7, 29, 8, 36, - 7, 36, 55, 36, 79, 33, 79, 36, 66, 8, - 36, 60, 33, 17, 33, 7, 2, 8, 36, 79, - 36, 2, 7, 7, 7, 66, 8, 33, 33, 7, - -1, 33, 8, 48, 8, 15, 15, 33, 36, 36, - 33, 8, 55, 7, 8, 8, 15, 6, 48, 10, - 8, 60, 8, 61, 34, 34, 8, 60, 8, 60, - 55, 20, 8, -1, 8, 34, 8, 61, 62, 8, - 40, 61, 62, 61, 62, 50, 42, 8, 60, 54, - 56, 51, 7, -1, 61, 62, 60, 53, 61, 62, - 61, 62, 8, 60, 55, 40, 29, 60, 56, -1, - 56, 29, 91, 92, 61, 62, 51, 61, 62, 61, - 60, 40, 56, 15, 60, 50, -1, 56, 60, 54, - 61, 62, 51, 1, 61, 62, 91, 92, 40, 60, - 29, 25, 34, 27, 36, -1, 61, 62, 12, 51, - 61, 62, 75, 12, 38, 61, 62, 75, 25, 25, - 27, 27, 25, 86, 27, 12, 7, 25, 86, 27, - 15, 38, 38, 29, 25, 38, 27, 25, 89, 27, - 38, 25, 25, 27, 27, 7, 75, 38, 15, 34, - 38, 36, 8, 57, 38, 38, 29, 86, 57, 63, - 61, 62, 36, 29, 63, 8, -1, 34, -1, 36, - 57, 25, 25, 27, 27, -1, 63, -1, -1, 75, - 61, 62, 15, -1, 38, 38, -1, 61, 62, -1, - 86, 25, 93, 27, 25, -1, 27, -1, 7, 61, - 62, 34, 75, 36, 38, 61, 62, 38, 47, 75, - 18, 19, -1, 86, 18, 19, 18, 19, 61, 62, - 86, -1, 61, 62, 33, 18, 19, 98, 99, 100, - 101, 102, 103, -1, -1, -1, -1, 45, 46, -1, - -1, 45, 46, 45, 46, -1, 23, 24, -1, -1, - 23, 24, 45, 46, 93, 32, 23, 24, 35, 32, - 37, -1, 35, -1, 37, 32, 23, 24, 35, -1, - 37, 29, 23, 24, 29, 32, -1, -1, 35, -1, - 37, 32, 23, 24, 35, 94, 37, 29, -1, -1, - 31, 32, 23, 24, 35, 29, 37, 15, -1, -1, - 31, 32, -1, -1, 35, 29, 37, -1, 66, 67, - 68, 66, 67, 68, -1, 33, 34, -1, 36, 29, - -1, -1, -1, -1, 66, 67, 68, 29, -1, -1, - -1, -1, 66, 67, 68, -1, 94, 95, 96, 94, - 95, 96, 66, 67, 68, -1, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, 66, 67, 68, -1, - 94, 95, 96, -1, 66, 67, 68, 29, -1, -1, - 94, 95, 96, 29, -1, -1, 29, -1, -1, 29, - -1, -1, 29, -1, 94, 95, 96, 29, 23, 24, - 29, -1, 94, 95, 96, -1, 31, 32, -1, -1, - 35, -1, 37, -1, 66, 67, 68, -1, -1, -1, - 66, 67, 68, 66, 67, 68, 66, 67, 68, 66, - 67, 68, -1, 29, 66, 67, 68, 66, 67, 68, - 36, -1, 94, 95, 96, -1, -1, -1, 94, 95, - 96, 94, 95, 96, 94, 95, 96, 94, 95, 96, - -1, -1, 94, 95, 96, 94, 95, 96, 29, -1, - 66, 67, 68, 29, -1, 36, 29, -1, -1, -1, - 36, 29, -1, -1, 29, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 94, 95, - 96, -1, -1, -1, -1, 66, 67, 68, 61, 62, - 66, 67, 68, 66, 67, 68, 61, 62, 66, 67, - 68, 66, 67, 68, -1, -1, -1, 29, -1, -1, + 36, 60, 5, 36, 31, 7, 66, 16, 33, 7, + 36, 7, 7, 7, 7, 33, 36, 7, 55, 8, + 36, 7, 7, 36, 7, 55, 7, 7, 36, 36, + 17, 7, 33, 33, 7, 7, 7, 36, 7, 36, + 7, 7, 34, 60, 55, 36, 7, 66, 60, 33, + 55, 33, 7, 77, 33, 8, 60, 20, 36, 33, + 1, 36, 8, 33, 7, 33, 2, 55, 33, 33, + 29, 1, 24, 33, 8, 1, -1, 2, 55, -1, + 37, 8, 36, -1, -1, -1, 8, 36, 36, 33, + 7, 2, 48, 1, 36, 7, 36, 36, 60, 36, + 33, 17, 60, 8, 0, 36, 8, 2, -1, 60, + 60, 8, 6, -1, 61, 7, 8, 8, 33, 8, + -1, 8, 60, 55, 48, 60, 20, 48, 8, 36, + 8, 10, 8, 61, 79, 55, -1, -1, 48, 8, + 8, 40, 40, 61, 8, 8, 60, 5, 61, 62, + 79, 60, 51, 51, 56, 40, 79, 61, 62, 40, + 79, 61, 62, 60, 50, 8, 51, 56, 54, 60, + 51, 61, 62, 60, 8, 50, 55, 61, 62, 54, + 60, 29, 60, 42, 60, 91, 92, 56, 56, 61, + 62, 61, 62, 56, 53, 15, 60, 8, 7, 61, + 62, 61, 62, 29, 61, 62, 29, 25, 8, 27, + 7, -1, 15, 29, 34, 8, 36, 25, 61, 27, + 38, 12, -1, 25, 33, 27, 60, 75, 12, 36, + 38, 34, 89, 36, 29, 7, 38, 29, 86, -1, + 25, 12, 27, 25, 25, 27, 27, 7, 15, 75, + 61, 62, 75, 38, 61, 62, 38, 38, -1, 75, + 86, 61, 62, 86, 61, 62, 57, 34, 61, 62, + 86, -1, 63, 57, 15, 61, 62, 15, -1, 63, + 75, 18, 19, 75, -1, 94, 57, 18, 19, 61, + 62, 86, 63, 34, 86, 36, 34, 47, 36, 18, + 19, 61, 62, 15, -1, 18, 19, 93, 45, 46, + 15, 61, 62, -1, 45, 46, -1, -1, -1, -1, + -1, 33, 34, -1, 36, -1, 45, 46, 33, 34, + -1, 36, 45, 46, -1, 23, 24, -1, -1, 25, + -1, 27, -1, 93, 32, 23, 24, 35, 29, 37, + -1, -1, 38, 31, 32, -1, -1, 35, 29, 37, + 23, 24, 98, 99, 100, 101, 102, 103, 31, 32, + 23, 24, 35, 29, 37, -1, -1, -1, 31, 32, + 23, 24, 35, -1, 37, 66, 67, 68, 31, 32, + 23, 24, 35, -1, 37, 66, 67, 68, 31, 32, + -1, -1, 35, -1, 37, 29, -1, -1, 29, -1, + 66, 67, 68, 94, 95, 96, 29, -1, -1, 29, + 23, 24, 29, 94, 95, 96, -1, -1, 29, 32, + -1, -1, 35, -1, 37, 36, -1, -1, 94, 95, + 96, 29, 66, 67, 68, 66, 67, 68, 36, -1, + -1, -1, -1, 66, 67, 68, 66, 67, 68, 66, + 67, 68, 29, -1, -1, 66, 67, 68, -1, 36, + 94, 95, 96, 94, 95, 96, -1, -1, 66, 67, + 68, 94, 95, 96, 94, 95, 96, 94, 95, 96, + -1, -1, -1, 94, 95, 96, -1, -1, 29, 66, + 67, 68, -1, 29, -1, -1, 94, 95, 96, -1, + -1, 29, -1, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, -1, -1, -1, -1, 94, 95, 96, + 61, 62, -1, -1, -1, 66, 67, 68, -1, -1, + 66, 67, 68, 61, 62, -1, -1, -1, 66, 67, + 68, 61, 62, -1, -1, -1, 66, 67, 68, -1, -1, -1, -1, 94, 95, 96, -1, -1, 94, 95, - 96, 94, 95, 96, -1, -1, 94, 95, 96, 94, - 95, 96, -1, -1, -1, -1, -1, -1, 29, 61, - 62, -1, -1, -1, 66, 67, 68, -1, -1, -1, + 96, -1, -1, -1, -1, -1, 94, 95, 96, -1, + 29, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 61, 62, 94, 95, 96, 66, 67, 68, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, - -1, -1, -1, 12, 13, 3, -1, -1, -1, -1, - -1, -1, -1, 22, -1, 13, -1, -1, -1, 17, - 29, -1, -1, -1, 33, 34, -1, 36, 26, -1, - 28, -1, -1, -1, 43, -1, -1, -1, 47, -1, - -1, 39, -1, 41, 42, -1, -1, -1, -1, -1, - -1, 49, -1, -1, 52, 53, 65, 66, 67, 68, - 58, 70, -1, -1, -1, -1, 64, -1, -1, -1, - -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, - -1, -1, 80, -1, -1, 94, 95, 96, -1, -1, - -1, -1, -1, -1, -1, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, 22, -1, -1, 3, -1, - -1, -1, 29, -1, -1, -1, 33, 34, 13, 36, - -1, -1, 17, -1, -1, -1, 43, -1, -1, -1, - 47, 26, -1, 28, -1, -1, 31, -1, -1, -1, - -1, -1, -1, -1, 39, -1, 41, 42, 65, 66, - 67, 68, -1, 70, 49, -1, -1, 52, 53, -1, - -1, -1, -1, 58, 81, 82, 83, -1, -1, 64, - 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, - -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, - -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, - -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, - -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, - -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, - -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, - 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, - 67, 68, -1, 70, -1, -1, -1, -1, -1, -1, + -1, -1, 61, 62, 3, -1, -1, 66, 67, 68, + -1, -1, -1, -1, 13, -1, -1, -1, 17, -1, + -1, -1, -1, -1, -1, -1, -1, 26, -1, 28, + -1, -1, 31, -1, -1, 94, 95, 96, -1, -1, + 39, -1, 41, 42, -1, 12, 13, 3, -1, -1, + 49, -1, -1, 52, 53, 22, -1, 13, -1, 58, + -1, 17, 29, -1, -1, 64, 33, 34, -1, 36, + 26, -1, 28, -1, -1, -1, 43, -1, -1, -1, + 47, 80, -1, 39, -1, 41, 42, -1, -1, -1, + -1, -1, -1, 49, -1, -1, 52, 53, 65, 66, + 67, 68, 58, 70, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, - 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, - -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, - -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, - -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, + 87, -1, -1, -1, 80, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, - -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, - 81, 82, 83, 84, -1, -1, 87, -1, -1, -1, - -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 10, -1, 12, 13, -1, - -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, - -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, - -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, - -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, - 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, - 75, -1, -1, -1, -1, -1, 81, 82, 83, 84, - -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, - 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, -1, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, - -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, - -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, - -1, 70, -1, -1, -1, -1, 75, -1, -1, -1, - -1, -1, 81, 82, 83, 84, -1, -1, 87, -1, - -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, - -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, - -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, - 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, - 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, - -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, - 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 7, -1, -1, -1, 11, 12, 13, -1, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, + -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, + -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, + 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, + -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 10, -1, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, + -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, 68, -1, 70, -1, -1, -1, -1, 75, + -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, + -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, + 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, + -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, + -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, + -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, @@ -879,101 +844,100 @@ const short QQmlJSGrammar::action_check [] = { -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, - -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, - -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, - 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, - -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, - 70, -1, 72, -1, 74, 75, 76, -1, -1, -1, - -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, - -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, - 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, - 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, 53, -1, -1, 56, -1, -1, -1, -1, -1, - -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, - 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, - 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, - -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, - -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, - 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, - -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, - 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, - -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, - 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, 7, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, - -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, - -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, - -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, -1, 56, -1, - -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, - 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, - -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, - -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, + 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, + -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, + -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, + 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, + -1, 72, -1, 74, 75, 76, -1, -1, -1, -1, + 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, + -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, - -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, + -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, - 53, -1, -1, -1, -1, -1, -1, -1, 61, -1, - -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, - 73, 74, -1, 76, -1, 78, -1, -1, 81, 82, + 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, + -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, + -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, - -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, - -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, - -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, - -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, - 68, 69, 70, -1, 72, 73, 74, -1, 76, -1, - 78, -1, -1, 81, 82, 83, -1, -1, -1, 87, - -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, - 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, - 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, - -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, - 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, - 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, - 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, - 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, - 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, - -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, - -1, 65, 66, 67, 68, 69, 70, 71, -1, 73, - 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, - 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, + -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, + -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, + -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, + -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, + 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, + -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, + -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, + 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, + -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, + -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, + -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, + 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, + -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, + 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, + -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, + -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, + 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, + -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, + -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, + -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, + -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, + -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, + 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, + -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, + 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, + -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, + 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, + -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, + -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, + -1, -1, 61, -1, -1, -1, 65, 66, 67, 68, + 69, 70, -1, 72, 73, 74, -1, 76, -1, 78, + -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, + -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, + -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, + 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, + -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, - -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, + -1, -1, -1, -1, 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, @@ -982,95 +946,126 @@ const short QQmlJSGrammar::action_check [] = { 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, - -1, -1, -1, -1, -1, 55, -1, -1, -1, 59, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, - -1, 9, -1, 11, 12, 13, 14, -1, -1, -1, - -1, -1, -1, 21, 22, -1, -1, -1, -1, -1, - -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, - -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, - -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, -1, -1, 81, 82, 83, 84, 85, -1, 87, + -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, + -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, + -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, + 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, - -1, -1, -1, 9, -1, 11, 12, 13, 14, -1, - -1, -1, -1, -1, -1, 21, 22, -1, -1, -1, - -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, + 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, + 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, + -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, + -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, - -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, + 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, - 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, - -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, + 4, -1, -1, -1, -1, 9, -1, 11, 12, 13, + 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, - 84, 85, 86, 87, -1, -1, -1, -1, -1, -1, + 84, 85, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, - 12, 13, 14, -1, 16, -1, -1, -1, 20, 21, - 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, - 32, 33, 34, -1, 36, -1, -1, -1, 40, -1, + -1, -1, 4, -1, -1, -1, -1, 9, -1, 11, + 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, + 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, 53, -1, 55, -1, -1, -1, 59, -1, 61, + -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, - 82, 83, 84, 85, 86, 87, -1, -1, -1, -1, + 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, + -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, + 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, + 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, + -1, 81, 82, 83, 84, 85, 86, 87, -1, -1, + -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, + -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, + -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, + -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, 55, -1, -1, + -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, -1, -1, 81, 82, 83, 84, 85, 86, 87, + -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, + -1, -1, -1, -1, -1, -1, -1, -1, - 42, 3, 18, 25, 18, 3, 18, 3, 18, 22, - 18, 3, 18, 22, 32, 32, 42, 18, 18, 18, - 3, 32, 25, 18, 18, 32, 3, 18, 32, 105, - 18, 18, 25, 100, 3, 3, 3, 18, 3, 25, - 18, 3, 18, 18, 18, 42, 3, 3, 103, 9, - 3, 14, 42, 42, 18, 25, 14, 42, 42, 18, - 42, 3, 42, 18, 18, 3, 18, 3, 18, 14, - 42, 22, 18, 2, 4, 18, 42, 18, 2, 11, - 12, 54, -1, 54, 2, 56, 59, 18, 18, 18, - 4, 14, 14, 54, 18, 56, 19, 14, 77, 14, - 18, 23, 2, 46, 18, 54, 54, 54, 2, 2, - 59, 59, 59, 18, 54, 54, 3, 56, 18, 59, - 54, 54, 56, 56, 18, 18, 54, 54, 54, 56, - 56, 59, 18, 54, 51, 56, 51, 2, 54, 2, - 56, 54, 54, 56, 56, 54, 54, 56, 38, 2, - 58, 54, 42, 18, 57, 18, 3, 54, 2, 45, - 18, 92, 54, 54, 2, 18, 3, 18, 109, 66, - 42, 54, 64, 56, 18, 18, 18, 2, 50, 70, - 18, 54, 42, 4, 54, 43, 56, 18, 14, 94, - 50, 78, 2, 18, 45, 68, 18, 18, 54, 18, - 56, 3, 54, 46, 46, 54, 54, 59, 18, 54, - 2, 60, 60, 44, 54, 60, 56, 2, 14, 14, - 3, 54, 44, 19, 19, 51, 18, 60, 47, 2, - 54, 78, 18, 18, 54, -1, 56, 54, 62, 56, - 54, 54, 18, 18, 58, 18, 59, 54, 54, 54, - 57, 54, 58, 54, 59, 54, 59, 54, 59, 45, - 59, 54, 59, 54, 2, 2, 59, -1, 59, 45, - 61, -1, 47, 48, 2, -1, 78, 54, -1, 76, - 18, 18, 59, 76, 54, -1, 54, 54, 54, 59, - 18, 59, 59, 59, -1, 78, -1, -1, 54, 76, - 54, 69, -1, 59, 71, 59, 76, 61, 54, 54, - 76, 67, 54, 59, 59, 61, 5, 59, 54, 61, - 65, 14, 5, 59, -1, 14, 19, 63, 21, -1, - -1, 14, -1, -1, 23, -1, -1, -1, -1, -1, - 23, -1, -1, -1, -1, -1, 35, 36, -1, 42, - 88, 88, 35, 36, 25, 26, 27, 28, 29, 30, - 31, 24, 25, 26, 27, 28, 29, 30, 31, -1, + 32, 22, 18, 9, 18, 42, 18, 14, 32, 3, + 18, 3, 3, 18, 18, 32, 18, 32, 3, 22, + 3, 18, 3, 18, 25, 18, 22, 14, 18, 18, + 14, 42, 18, 32, 22, 77, 3, 100, 3, 3, + 3, 103, 42, 18, 42, 18, 3, 3, 25, 25, + 3, 105, 18, 25, 3, 3, 18, 18, 3, 18, + 42, 3, 42, 42, 42, 25, 18, 18, 42, 2, + -1, 18, 18, 42, 18, 18, 14, 18, 14, 18, + 2, 4, 2, 18, 42, 18, 54, 14, 56, 18, + -1, 4, -1, 18, -1, 18, 18, 18, 18, 54, + 54, 56, 56, 44, 54, 18, 56, 18, 11, 12, + 45, -1, -1, 51, 54, 51, 56, 54, 42, 56, + 54, 46, 54, 54, 51, 46, 50, 59, 59, 18, + 42, -1, -1, -1, 45, 54, 70, 54, 50, 54, + 59, 14, 59, 2, 59, 54, 19, 56, 54, 54, + 54, 56, 14, 59, 43, 54, 54, 56, 56, 18, + 2, 23, 2, 54, 68, 56, 14, 54, 54, 2, + 54, 19, 3, 60, 60, 59, 18, 54, 18, 18, + 109, 18, 59, 54, 54, 18, 54, 54, 59, 59, + 54, 59, 59, 54, 58, 38, 54, 58, 18, 42, + 58, 2, 54, 2, 18, 54, 45, 2, 45, 2, + 4, 3, 18, 18, 66, 64, 3, 18, 54, 18, + 56, 2, 54, 18, 18, 18, 46, 54, 60, 56, + 3, 3, 54, 47, 2, 57, 54, 18, 56, 54, + 2, 56, 54, 54, 56, 2, 57, 54, 2, 18, + 18, 54, 54, 56, -1, 62, 18, 54, 60, 56, + -1, 18, 14, 54, 18, 54, 2, 19, 59, -1, + 59, 54, 54, -1, 63, 44, 59, 59, -1, 54, + 2, -1, 18, 65, 59, 76, 78, 92, 94, 54, + 54, 78, 18, 76, 59, 59, 18, 61, 54, 54, + -1, 76, 67, 59, 59, 78, 78, 54, 54, -1, + 54, 54, 59, 59, 69, 59, 59, 61, 61, 14, + 76, 47, 48, -1, 71, -1, 54, 14, 23, 5, + 76, 59, 19, 61, 21, 5, -1, -1, 14, -1, + 35, 36, -1, -1, 14, -1, -1, 23, -1, -1, + -1, -1, 88, 23, -1, 42, -1, -1, -1, 35, + 36, -1, -1, -1, -1, 35, 36, 25, 26, 27, + 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, + -1, 14, -1, -1, -1, -1, -1, -1, -1, 2, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 14, + -1, -1, -1, -1, -1, 18, -1, -1, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 14, 14, -1, -1, -1, -1, -1, - -1, -1, 23, 23, 24, 25, 26, 27, 28, 29, - 30, 31, -1, -1, 35, 36, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 88, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, + -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, + 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -1078,15 +1073,6 @@ const short QQmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 14, -1, -1, -1, -1, -1, -1, -1, -1, 23, - 24, 25, 26, 27, 28, 29, 30, 31, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1}; + -1, -1, -1, -1, -1}; QT_END_NAMESPACE diff --git a/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h b/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h index 6b3d1c8013..7a369be194 100644 --- a/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h +++ b/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h @@ -161,15 +161,15 @@ public: T_XOR = 79, T_XOR_EQ = 80, - ACCEPT_STATE = 663, - RULE_COUNT = 357, - STATE_COUNT = 664, + ACCEPT_STATE = 665, + RULE_COUNT = 358, + STATE_COUNT = 666, TERMINAL_COUNT = 106, NON_TERMINAL_COUNT = 111, - GOTO_INDEX_OFFSET = 664, - GOTO_INFO_OFFSET = 3104, - GOTO_CHECK_OFFSET = 3104 + GOTO_INDEX_OFFSET = 666, + GOTO_INFO_OFFSET = 3018, + GOTO_CHECK_OFFSET = 3018 }; static const char *const spell []; diff --git a/src/tools/qdoc/qmlparser/qqmljsparser.cpp b/src/tools/qdoc/qmlparser/qqmljsparser.cpp index 262043b3b8..762e60c827 100644 --- a/src/tools/qdoc/qmlparser/qqmljsparser.cpp +++ b/src/tools/qdoc/qmlparser/qqmljsparser.cpp @@ -567,56 +567,78 @@ case 69: { } break; case 70: { - sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); + AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4)); + node->isReadonlyMember = true; + node->readonlyToken = loc(1); + node->propertyToken = loc(2); + node->typeToken = loc(3); + node->identifierToken = loc(4); + node->semicolonToken = loc(5); // insert a fake ';' before ':' + + AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(4)); + propertyName->identifierToken = loc(4); + propertyName->next = 0; + + AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding( + propertyName, sym(6).UiQualifiedId, sym(7).UiObjectInitializer); + binding->colonToken = loc(5); + + node->binding = binding; + + sym(1).Node = node; } break; case 71: { sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); } break; -case 79: { +case 72: { + sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node); +} break; + +case 80: { AST::ThisExpression *node = new (pool) AST::ThisExpression(); node->thisToken = loc(1); sym(1).Node = node; } break; -case 80: { +case 81: { AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 81: { +case 82: { AST::NullExpression *node = new (pool) AST::NullExpression(); node->nullToken = loc(1); sym(1).Node = node; } break; -case 82: { +case 83: { AST::TrueLiteral *node = new (pool) AST::TrueLiteral(); node->trueToken = loc(1); sym(1).Node = node; } break; -case 83: { +case 84: { AST::FalseLiteral *node = new (pool) AST::FalseLiteral(); node->falseToken = loc(1); sym(1).Node = node; } break; -case 84: { +case 85: { AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval); node->literalToken = loc(1); sym(1).Node = node; } break; -case 85: -case 86: { +case 86: +case 87: { AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1)); node->literalToken = loc(1); sym(1).Node = node; } break; -case 87: { +case 88: { bool rx = lexer->scanRegExp(Lexer::NoPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -632,7 +654,7 @@ case 87: { sym(1).Node = node; } break; -case 88: { +case 89: { bool rx = lexer->scanRegExp(Lexer::EqualPrefix); if (!rx) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage())); @@ -648,28 +670,28 @@ case 88: { sym(1).Node = node; } break; -case 89: { +case 90: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0); node->lbracketToken = loc(1); node->rbracketToken = loc(2); sym(1).Node = node; } break; -case 90: { +case 91: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -case 91: { +case 92: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ()); node->lbracketToken = loc(1); node->rbracketToken = loc(3); sym(1).Node = node; } break; -case 92: { +case 93: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), (AST::Elision *) 0); node->lbracketToken = loc(1); @@ -678,7 +700,7 @@ case 92: { sym(1).Node = node; } break; -case 93: { +case 94: { AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (), sym(4).Elision->finish()); node->lbracketToken = loc(1); @@ -687,7 +709,7 @@ case 93: { sym(1).Node = node; } break; -case 94: { +case 95: { AST::ObjectLiteral *node = 0; if (sym(2).Node) node = new (pool) AST::ObjectLiteral( @@ -699,7 +721,7 @@ case 94: { sym(1).Node = node; } break; -case 95: { +case 96: { AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral( sym(2).PropertyAssignmentList->finish ()); node->lbraceToken = loc(1); @@ -707,14 +729,14 @@ case 95: { sym(1).Node = node; } break; -case 96: { +case 97: { AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression); node->lparenToken = loc(1); node->rparenToken = loc(3); sym(1).Node = node; } break; -case 97: { +case 98: { if (AST::ArrayMemberExpression *mem = AST::cast(sym(1).Expression)) { diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken, QLatin1String("Ignored annotation"))); @@ -734,48 +756,48 @@ case 97: { } } break; -case 98: { +case 99: { sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression); } break; -case 99: { +case 100: { sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression); } break; -case 100: { +case 101: { AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, (AST::Elision *) 0, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 101: { +case 102: { AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(), sym(4).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 102: { +case 103: { AST::Elision *node = new (pool) AST::Elision(); node->commaToken = loc(1); sym(1).Node = node; } break; -case 103: { +case 104: { AST::Elision *node = new (pool) AST::Elision(sym(1).Elision); node->commaToken = loc(2); sym(1).Node = node; } break; -case 104: { +case 105: { AST::PropertyNameAndValue *node = new (pool) AST::PropertyNameAndValue( sym(1).PropertyName, sym(3).Expression); node->colonToken = loc(2); sym(1).Node = node; } break; -case 105: { +case 106: { AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter( sym(2).PropertyName, sym(6).FunctionBody); node->getSetToken = loc(1); @@ -786,7 +808,7 @@ case 105: { sym(1).Node = node; } break; -case 106: { +case 107: { AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter( sym(2).PropertyName, sym(4).FormalParameterList, sym(7).FunctionBody); node->getSetToken = loc(1); @@ -797,56 +819,56 @@ case 106: { sym(1).Node = node; } break; -case 107: { +case 108: { sym(1).Node = new (pool) AST::PropertyAssignmentList(sym(1).PropertyAssignment); } break; -case 108: { +case 109: { AST::PropertyAssignmentList *node = new (pool) AST::PropertyAssignmentList( sym(1).PropertyAssignmentList, sym(3).PropertyAssignment); node->commaToken = loc(2); sym(1).Node = node; } break; -case 109: { - AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); - node->propertyNameToken = loc(1); - sym(1).Node = node; -} break; - case 110: { - AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); + AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 111: { - AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); + AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; case 112: { + AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval); + node->propertyNameToken = loc(1); + sym(1).Node = node; +} break; + +case 113: { AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1)); node->propertyNameToken = loc(1); sym(1).Node = node; } break; -case 148: { +case 149: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 149: { +case 150: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 150: { +case 151: { AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); @@ -854,19 +876,12 @@ case 150: { sym(1).Node = node; } break; -case 152: { +case 153: { AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; -case 153: { - AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); - node->lparenToken = loc(2); - node->rparenToken = loc(4); - sym(1).Node = node; -} break; - case 154: { AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); @@ -875,363 +890,370 @@ case 154: { } break; case 155: { + AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); + node->lparenToken = loc(2); + node->rparenToken = loc(4); + sym(1).Node = node; +} break; + +case 156: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 156: { +case 157: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 157: { +case 158: { sym(1).Node = 0; } break; -case 158: { +case 159: { sym(1).Node = sym(1).ArgumentList->finish(); } break; -case 159: { +case 160: { sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression); } break; -case 160: { +case 161: { AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 164: { +case 165: { AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; -case 165: { +case 166: { AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; -case 167: { +case 168: { AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; -case 168: { +case 169: { AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; -case 169: { +case 170: { AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; -case 170: { +case 171: { AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; -case 171: { +case 172: { AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; -case 172: { +case 173: { AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; -case 173: { +case 174: { AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; -case 174: { +case 175: { AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; -case 175: { +case 176: { AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; -case 177: { +case 178: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 178: { +case 179: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 179: { +case 180: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 181: { +case 182: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 182: { +case 183: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 184: { +case 185: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 185: { +case 186: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 186: { +case 187: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 188: { - AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Lt, sym(3).Expression); - node->operatorToken = loc(2); - sym(1).Node = node; -} break; - case 189: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Gt, sym(3).Expression); + QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 190: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Le, sym(3).Expression); + QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 191: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Ge, sym(3).Expression); + QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 192: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::InstanceOf, sym(3).Expression); + QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 193: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::In, sym(3).Expression); + QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 195: { +case 194: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Lt, sym(3).Expression); + QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 196: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Gt, sym(3).Expression); + QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 197: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Le, sym(3).Expression); + QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 198: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Ge, sym(3).Expression); + QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 199: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::InstanceOf, sym(3).Expression); + QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 201: { +case 200: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Equal, sym(3).Expression); + QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 202: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::NotEqual, sym(3).Expression); + QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 203: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::StrictEqual, sym(3).Expression); + QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 204: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::StrictNotEqual, sym(3).Expression); + QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 206: { +case 205: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::Equal, sym(3).Expression); + QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 207: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::NotEqual, sym(3).Expression); + QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 208: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - QSOperator::StrictEqual, sym(3).Expression); + QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; case 209: { + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + QSOperator::StrictEqual, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; +} break; + +case 210: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 211: { +case 212: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 213: { +case 214: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 215: { +case 216: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 217: { +case 218: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 219: { +case 220: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 221: { +case 222: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 223: { +case 224: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 225: { +case 226: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 227: { +case 228: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 229: { +case 230: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 231: { +case 232: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1239,7 +1261,7 @@ case 231: { sym(1).Node = node; } break; -case 233: { +case 234: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1247,14 +1269,7 @@ case 233: { sym(1).Node = node; } break; -case 235: { - AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, - sym(2).ival, sym(3).Expression); - node->operatorToken = loc(2); - sym(1).Node = node; -} break; - -case 237: { +case 236: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); @@ -1262,97 +1277,104 @@ case 237: { } break; case 238: { - sym(1).ival = QSOperator::Assign; + AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, + sym(2).ival, sym(3).Expression); + node->operatorToken = loc(2); + sym(1).Node = node; } break; case 239: { - sym(1).ival = QSOperator::InplaceMul; + sym(1).ival = QSOperator::Assign; } break; case 240: { - sym(1).ival = QSOperator::InplaceDiv; + sym(1).ival = QSOperator::InplaceMul; } break; case 241: { - sym(1).ival = QSOperator::InplaceMod; + sym(1).ival = QSOperator::InplaceDiv; } break; case 242: { - sym(1).ival = QSOperator::InplaceAdd; + sym(1).ival = QSOperator::InplaceMod; } break; case 243: { - sym(1).ival = QSOperator::InplaceSub; + sym(1).ival = QSOperator::InplaceAdd; } break; case 244: { - sym(1).ival = QSOperator::InplaceLeftShift; + sym(1).ival = QSOperator::InplaceSub; } break; case 245: { - sym(1).ival = QSOperator::InplaceRightShift; + sym(1).ival = QSOperator::InplaceLeftShift; } break; case 246: { - sym(1).ival = QSOperator::InplaceURightShift; + sym(1).ival = QSOperator::InplaceRightShift; } break; case 247: { - sym(1).ival = QSOperator::InplaceAnd; + sym(1).ival = QSOperator::InplaceURightShift; } break; case 248: { - sym(1).ival = QSOperator::InplaceXor; + sym(1).ival = QSOperator::InplaceAnd; } break; case 249: { + sym(1).ival = QSOperator::InplaceXor; +} break; + +case 250: { sym(1).ival = QSOperator::InplaceOr; } break; -case 251: { - AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); - node->commaToken = loc(2); - sym(1).Node = node; -} break; - case 252: { - sym(1).Node = 0; -} break; - -case 255: { AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; +case 253: { + sym(1).Node = 0; +} break; + case 256: { + AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); + node->commaToken = loc(2); + sym(1).Node = node; +} break; + +case 257: { sym(1).Node = 0; } break; -case 273: { +case 274: { AST::Block *node = new (pool) AST::Block(sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 274: { +case 275: { sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); } break; -case 275: { +case 276: { sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement); } break; -case 276: { +case 277: { sym(1).Node = 0; } break; -case 277: { +case 278: { sym(1).Node = sym(1).StatementList->finish (); } break; -case 279: { +case 280: { AST::VariableStatement *node = new (pool) AST::VariableStatement( sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); node->declarationKindToken = loc(1); @@ -1360,37 +1382,31 @@ case 279: { sym(1).Node = node; } break; -case 280: { +case 281: { sym(1).ival = T_CONST; } break; -case 281: { +case 282: { sym(1).ival = T_VAR; } break; -case 282: { +case 283: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; -case 283: { +case 284: { AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList( sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; -case 284: { +case 285: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; -case 285: { - sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); -} break; - case 286: { - AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); - node->identifierToken = loc(1); - sym(1).Node = node; + sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; case 287: { @@ -1400,36 +1416,42 @@ case 287: { } break; case 288: { - // ### TODO: AST for initializer - sym(1) = sym(2); + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + node->identifierToken = loc(1); + sym(1).Node = node; } break; case 289: { - sym(1).Node = 0; -} break; - -case 291: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -case 292: { +case 290: { sym(1).Node = 0; } break; -case 294: { +case 292: { + // ### TODO: AST for initializer + sym(1) = sym(2); +} break; + +case 293: { + sym(1).Node = 0; +} break; + +case 295: { AST::EmptyStatement *node = new (pool) AST::EmptyStatement(); node->semicolonToken = loc(1); sym(1).Node = node; } break; -case 296: { +case 297: { AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 297: { +case 298: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1438,7 +1460,7 @@ case 297: { sym(1).Node = node; } break; -case 298: { +case 299: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1446,7 +1468,7 @@ case 298: { sym(1).Node = node; } break; -case 301: { +case 302: { AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); @@ -1456,7 +1478,7 @@ case 301: { sym(1).Node = node; } break; -case 302: { +case 303: { AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); @@ -1464,7 +1486,7 @@ case 302: { sym(1).Node = node; } break; -case 303: { +case 304: { AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); @@ -1475,7 +1497,7 @@ case 303: { sym(1).Node = node; } break; -case 304: { +case 305: { AST::LocalForStatement *node = new (pool) AST::LocalForStatement( sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, sym(8).Expression, sym(10).Statement); @@ -1488,7 +1510,7 @@ case 304: { sym(1).Node = node; } break; -case 305: { +case 306: { AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); @@ -1498,7 +1520,7 @@ case 305: { sym(1).Node = node; } break; -case 306: { +case 307: { AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement( sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); @@ -1509,14 +1531,14 @@ case 306: { sym(1).Node = node; } break; -case 308: { +case 309: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 310: { +case 311: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2)); node->continueToken = loc(1); node->identifierToken = loc(2); @@ -1524,14 +1546,14 @@ case 310: { sym(1).Node = node; } break; -case 312: { +case 313: { AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 314: { +case 315: { AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2)); node->breakToken = loc(1); node->identifierToken = loc(2); @@ -1539,14 +1561,14 @@ case 314: { sym(1).Node = node; } break; -case 316: { +case 317: { AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 317: { +case 318: { AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); @@ -1554,7 +1576,7 @@ case 317: { sym(1).Node = node; } break; -case 318: { +case 319: { AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); @@ -1562,83 +1584,83 @@ case 318: { sym(1).Node = node; } break; -case 319: { +case 320: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 320: { +case 321: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; -case 321: { +case 322: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause); } break; -case 322: { +case 323: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause); } break; -case 323: { +case 324: { sym(1).Node = 0; } break; -case 324: { +case 325: { sym(1).Node = sym(1).CaseClauses->finish (); } break; -case 325: { +case 326: { AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; -case 326: { +case 327: { AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 327: { +case 328: { AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 329: { +case 330: { AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 330: { +case 331: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; -case 331: { +case 332: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 332: { +case 333: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 333: { +case 334: { AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); @@ -1647,20 +1669,20 @@ case 333: { sym(1).Node = node; } break; -case 334: { +case 335: { AST::Finally *node = new (pool) AST::Finally(sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; -case 336: { +case 337: { AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement(); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 338: { +case 339: { AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); @@ -1671,7 +1693,7 @@ case 338: { sym(1).Node = node; } break; -case 339: { +case 340: { AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (! stringRef(2).isNull()) @@ -1683,7 +1705,7 @@ case 339: { sym(1).Node = node; } break; -case 340: { +case 341: { AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody); node->functionToken = loc(1); node->lparenToken = loc(2); @@ -1693,56 +1715,56 @@ case 340: { sym(1).Node = node; } break; -case 341: { +case 342: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 342: { +case 343: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 343: { - sym(1).Node = 0; -} break; - case 344: { - sym(1).Node = sym(1).FormalParameterList->finish (); + sym(1).Node = 0; } break; case 345: { + sym(1).Node = sym(1).FormalParameterList->finish (); +} break; + +case 346: { sym(1).Node = 0; } break; -case 347: { +case 348: { sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); } break; -case 349: { +case 350: { sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); } break; -case 350: { +case 351: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); } break; -case 351: { +case 352: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); } break; -case 352: { +case 353: { sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); } break; -case 353: { +case 354: { sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); } break; -case 354: { +case 355: { sym(1).Node = 0; } break; diff --git a/src/tools/qdoc/qmlparser/qqmljsparser_p.h b/src/tools/qdoc/qmlparser/qqmljsparser_p.h index b0abf06b25..cf9f641fbc 100644 --- a/src/tools/qdoc/qmlparser/qqmljsparser_p.h +++ b/src/tools/qdoc/qmlparser/qqmljsparser_p.h @@ -240,9 +240,9 @@ protected: -#define J_SCRIPT_REGEXPLITERAL_RULE1 87 +#define J_SCRIPT_REGEXPLITERAL_RULE1 88 -#define J_SCRIPT_REGEXPLITERAL_RULE2 88 +#define J_SCRIPT_REGEXPLITERAL_RULE2 89 QT_QML_END_NAMESPACE From 76735f3fa0fdf772aa4fba9a9aaa241415eaf922 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 5 Nov 2014 14:57:03 +0100 Subject: [PATCH 163/323] Windows native file dialog: Work around display bug of IFileDialog. Any filter not filtering on suffix shows up duplicated in filter combo. Change-Id: I9fc9e33b6081cf6894fabc6dd52c12a4d3dfd393 Task-number: QTBUG-42405 Reviewed-by: Joerg Bornemann --- .../platforms/windows/qwindowsdialoghelpers.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 4cbead44c5..f1f472b3e2 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1224,16 +1224,21 @@ void QWindowsNativeFileDialogBase::setNameFilters(const QStringList &filters) QScopedArrayPointer buffer(new WCHAR[totalStringLength + 2 * size]); QScopedArrayPointer comFilterSpec(new COMDLG_FILTERSPEC[size]); - const QString matchesAll = QStringLiteral(" (*)"); WCHAR *ptr = buffer.data(); // Split filter specification as 'Texts (*.txt[;] *.doc)' // into description and filters specification as '*.txt;*.doc' for (int i = 0; i < size; ++i) { - // Display glitch (CLSID only): 'All files (*)' shows up as 'All files (*) (*)' + // Display glitch (CLSID only): Any filter not filtering on suffix (such as + // '*', 'a.*') will be duplicated in combo: 'All files (*) (*)', + // 'AAA files (a.*) (a.*)' QString description = specs[i].description; - if (!m_hideFiltersDetails && description.endsWith(matchesAll)) - description.truncate(description.size() - matchesAll.size()); + const QString &filter = specs[i].filter; + if (!m_hideFiltersDetails && !filter.startsWith(QLatin1String("*."))) { + const int pos = description.lastIndexOf(QLatin1Char('(')); + if (pos > 0) + description.truncate(pos); + } // Add to buffer. comFilterSpec[i].pszName = ptr; ptr += description.toWCharArray(ptr); From 78cdb6b4b1c8c6213e967be56767d7dadd2bf8bf Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 5 Nov 2014 15:03:23 +0100 Subject: [PATCH 164/323] Windows: fix unreadable white text for focused combo boxes Task-number: QTBUG-42390 Change-Id: Ia52c7ac3d2e3ca155692c8f020a565054716c86b Reviewed-by: Friedemann Kleint --- src/widgets/styles/qwindowsvistastyle.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index 007952192a..463b120e04 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1473,7 +1473,11 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption break; } #endif // QT_NO_ITEMVIEWS - +#ifndef QT_NO_COMBOBOX + case CE_ComboBoxLabel: + QCommonStyle::drawControl(element, option, painter, widget); + break; +#endif // QT_NO_COMBOBOX default: QWindowsXPStyle::drawControl(element, option, painter, widget); break; From 8d82066ff5a00e2bc77716f90688550a6a779dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 5 Nov 2014 12:59:04 +0100 Subject: [PATCH 165/323] Skip unused function isCoreProfile() on non-ES2 platforms Change-Id: Ia84e74512e7001986c620253cdf0bc431ebc00dc Reviewed-by: Simon Hausmann --- src/gui/opengl/qopengltextureglyphcache.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp index 0f70a01014..cd268cd685 100644 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ b/src/gui/opengl/qopengltextureglyphcache.cpp @@ -82,10 +82,12 @@ QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() clear(); } +#if !defined(QT_OPENGL_ES_2) static inline bool isCoreProfile() { return QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile; } +#endif void QOpenGLTextureGlyphCache::createTextureData(int width, int height) { From af279b34a8ecccd7dfa0d59b718bc3cf65ebce65 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 27 Oct 2014 19:26:47 +1000 Subject: [PATCH 166/323] Reset QNAM's NetworkConfiguration when state changes. Since QNAM is initialized with defaultConfiguration, we need to reset the internal configuration used to the current defaultConfiguration when the state changes and a new configuration becomes the default. Task-number: QTBUG-40234 Change-Id: I50f23c62804f29370915eecac2c92301c5f3ead2 Reviewed-by: Kai Koehne Reviewed-by: Alex Blasche --- src/network/access/qnetworkaccessmanager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index f00b58a8ce..52d56fb071 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1135,7 +1135,12 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera if (!d->networkSessionStrongRef && (d->initializeSession || !d->networkConfiguration.identifier().isEmpty())) { QNetworkConfigurationManager manager; if (!d->networkConfiguration.identifier().isEmpty()) { - d->createSession(d->networkConfiguration); + if ((d->networkConfiguration.state() & QNetworkConfiguration::Defined) + && d->networkConfiguration != manager.defaultConfiguration()) + d->createSession(manager.defaultConfiguration()); + else + d->createSession(d->networkConfiguration); + } else { if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) d->createSession(manager.defaultConfiguration()); @@ -1590,6 +1595,11 @@ void QNetworkAccessManagerPrivate::_q_onlineStateChanged(bool isOnline) if (customNetworkConfiguration) { online = (networkConfiguration.state() & QNetworkConfiguration::Active); } else { + if (isOnline && online != isOnline) { + networkSessionStrongRef.clear(); + networkSessionWeakRef.clear(); + } + online = isOnline; } } From 4763a3571f3301dd2da6d35636a94e4d1dc1f216 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Wed, 29 Oct 2014 19:40:43 +1000 Subject: [PATCH 167/323] Use a property cache to cut down on blocking calls Refactor old code Stop memory leaks Properly support mobile data (ofono) Change-Id: I7f23882ee0ee345a049a4a93ddd452b6d2e53710 Reviewed-by: Alex Blasche --- src/plugins/bearer/connman/connman.pro | 4 +- src/plugins/bearer/connman/qconnmanengine.h | 2 +- .../qofonoservice_linux.cpp | 89 ++- .../qofonoservice_linux_p.h | 25 +- .../bearer/networkmanager/networkmanager.pro | 6 +- .../networkmanager/qnetworkmanagerengine.cpp | 364 ++++----- .../networkmanager/qnetworkmanagerengine.h | 22 +- .../networkmanager/qnetworkmanagerservice.cpp | 693 +++++++++++++----- .../networkmanager/qnetworkmanagerservice.h | 105 ++- .../bearer/networkmanager/qnmdbushelper.cpp | 140 ---- .../bearer/networkmanager/qnmdbushelper.h | 73 -- 11 files changed, 855 insertions(+), 668 deletions(-) rename src/plugins/bearer/{connman => linux_common}/qofonoservice_linux.cpp (76%) rename src/plugins/bearer/{connman => linux_common}/qofonoservice_linux_p.h (88%) delete mode 100644 src/plugins/bearer/networkmanager/qnmdbushelper.cpp delete mode 100644 src/plugins/bearer/networkmanager/qnmdbushelper.h diff --git a/src/plugins/bearer/connman/connman.pro b/src/plugins/bearer/connman/connman.pro index bc4efe8b62..efa13a6ebd 100644 --- a/src/plugins/bearer/connman/connman.pro +++ b/src/plugins/bearer/connman/connman.pro @@ -8,14 +8,14 @@ QT = core network-private dbus CONFIG += link_pkgconfig HEADERS += qconnmanservice_linux_p.h \ - qofonoservice_linux_p.h \ + ../linux_common/qofonoservice_linux_p.h \ qconnmanengine.h \ ../qnetworksession_impl.h \ ../qbearerengine_impl.h SOURCES += main.cpp \ qconnmanservice_linux.cpp \ - qofonoservice_linux.cpp \ + ../linux_common/qofonoservice_linux.cpp \ qconnmanengine.cpp \ ../qnetworksession_impl.cpp diff --git a/src/plugins/bearer/connman/qconnmanengine.h b/src/plugins/bearer/connman/qconnmanengine.h index 52e8b384a0..a995d8ed25 100644 --- a/src/plugins/bearer/connman/qconnmanengine.h +++ b/src/plugins/bearer/connman/qconnmanengine.h @@ -48,7 +48,7 @@ #include "../qbearerengine_impl.h" #include "qconnmanservice_linux_p.h" -#include "qofonoservice_linux_p.h" +#include "../linux_common/qofonoservice_linux_p.h" #include #include diff --git a/src/plugins/bearer/connman/qofonoservice_linux.cpp b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp similarity index 76% rename from src/plugins/bearer/connman/qofonoservice_linux.cpp rename to src/plugins/bearer/linux_common/qofonoservice_linux.cpp index 2ce2bd40e4..e994ebf2ce 100644 --- a/src/plugins/bearer/connman/qofonoservice_linux.cpp +++ b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp @@ -95,14 +95,12 @@ QStringList QOfonoManagerInterface::getModems() { if (modemList.isEmpty()) { QList argumentList; - QDBusPendingReply reply = asyncCallWithArgumentList(QLatin1String("GetModems"), argumentList); + QDBusPendingReply reply = callWithArgumentList(QDBus::Block, QLatin1String("GetModems"), argumentList); reply.waitForFinished(); if (!reply.isError()) { foreach (ObjectPathProperties modem, reply.value()) { modemList << modem.path.path(); } - } else { - qDebug() << reply.error().message(); } } @@ -175,7 +173,7 @@ QVariantMap QOfonoModemInterface::getProperties() { if (propertiesMap.isEmpty()) { QList argumentList; - QDBusPendingReply reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + QDBusPendingReply reply = callWithArgumentList(QDBus::Block, QLatin1String("GetProperties"), argumentList); if (!reply.isError()) { propertiesMap = reply.value(); } @@ -187,7 +185,8 @@ QVariant QOfonoModemInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - var = map.value(property); + if (map.contains(property)) + var = map.value(property); return var; } @@ -214,7 +213,8 @@ QVariant QOfonoNetworkRegistrationInterface::getProperty(const QString &property { QVariant var; QVariantMap map = getProperties(); - var = map.value(property); + if (map.contains(property)) + var = map.value(property); return var; } @@ -222,12 +222,10 @@ QVariantMap QOfonoNetworkRegistrationInterface::getProperties() { if (propertiesMap.isEmpty()) { QList argumentList; - QDBusPendingReply reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + QDBusPendingReply reply = callWithArgumentList(QDBus::Block, QLatin1String("GetProperties"), argumentList); reply.waitForFinished(); if (!reply.isError()) { propertiesMap = reply.value(); - } else { - qDebug() << reply.error().message(); } } return propertiesMap; @@ -270,11 +268,18 @@ bool QOfonoDataConnectionManagerInterface::roamingAllowed() return qdbus_cast(var); } +QString QOfonoDataConnectionManagerInterface::bearer() +{ + QVariant var = getProperty(QStringLiteral("Bearer")); + return qdbus_cast(var); +} + QVariant QOfonoDataConnectionManagerInterface::getProperty(const QString &property) { QVariant var; QVariantMap map = getProperties(); - var = map.value(property); + if (map.contains(property)) + var = map.value(property); return var; } @@ -282,7 +287,7 @@ QVariantMap QOfonoDataConnectionManagerInterface::getProperties() { if (propertiesMap.isEmpty()) { QList argumentList; - QDBusPendingReply reply = asyncCallWithArgumentList(QLatin1String("GetProperties"), argumentList); + QDBusPendingReply reply = callWithArgumentList(QDBus::Block, QLatin1String("GetProperties"), argumentList); if (!reply.isError()) { propertiesMap = reply.value(); } @@ -297,6 +302,68 @@ void QOfonoDataConnectionManagerInterface::propertyChanged(const QString &name, Q_EMIT roamingAllowedChanged(value.variant().toBool()); } + +QOfonoConnectionContextInterface::QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent) + : QDBusAbstractInterface(QLatin1String(OFONO_SERVICE), + dbusPathName, + OFONO_CONNECTION_CONTEXT_INTERFACE, + QDBusConnection::systemBus(), parent) +{ + QDBusConnection::systemBus().connect(QLatin1String(OFONO_SERVICE), + path(), + QLatin1String(OFONO_MODEM_INTERFACE), + QLatin1String("PropertyChanged"), + this,SLOT(propertyChanged(QString,QDBusVariant))); +} + +QOfonoConnectionContextInterface::~QOfonoConnectionContextInterface() +{ +} + +QVariantMap QOfonoConnectionContextInterface::getProperties() +{ + if (propertiesMap.isEmpty()) { + QList argumentList; + QDBusPendingReply reply = callWithArgumentList(QDBus::Block, QLatin1String("GetProperties"), argumentList); + if (!reply.isError()) { + propertiesMap = reply.value(); + } + } + return propertiesMap; +} + +void QOfonoConnectionContextInterface::propertyChanged(const QString &name, const QDBusVariant &value) +{ + propertiesMap[name] = value.variant(); +} + +QVariant QOfonoConnectionContextInterface::getProperty(const QString &property) +{ + QVariant var; + QVariantMap map = getProperties(); + if (map.contains(property)) + var = map.value(property); + return var; +} + +bool QOfonoConnectionContextInterface::active() +{ + QVariant var = getProperty(QStringLiteral("Active")); + return qdbus_cast(var); +} + +QString QOfonoConnectionContextInterface::accessPointName() +{ + QVariant var = getProperty(QStringLiteral("AccessPointName")); + return qdbus_cast(var); +} + +QString QOfonoConnectionContextInterface::name() +{ + QVariant var = getProperty(QStringLiteral("Name")); + return qdbus_cast(var); +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/connman/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h similarity index 88% rename from src/plugins/bearer/connman/qofonoservice_linux_p.h rename to src/plugins/bearer/linux_common/qofonoservice_linux_p.h index 8a6a932e0d..2b3d43deb5 100644 --- a/src/plugins/bearer/connman/qofonoservice_linux_p.h +++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h @@ -67,6 +67,7 @@ #define OFONO_MODEM_INTERFACE "org.ofono.Modem" #define OFONO_NETWORK_REGISTRATION_INTERFACE "org.ofono.NetworkRegistration" #define OFONO_DATA_CONNECTION_MANAGER_INTERFACE "org.ofono.ConnectionManager" +#define OFONO_CONNECTION_CONTEXT_INTERFACE "org.ofono.ConnectionContext" QT_BEGIN_NAMESPACE @@ -152,17 +153,39 @@ public: QStringList contexts(); bool roamingAllowed(); + QVariant getProperty(const QString &); + QString bearer(); Q_SIGNALS: void roamingAllowedChanged(bool); private: QVariantMap getProperties(); QVariantMap propertiesMap; - QVariant getProperty(const QString &); QStringList contextList; private slots: void propertyChanged(const QString &, const QDBusVariant &value); }; +class QOfonoConnectionContextInterface : public QDBusAbstractInterface +{ + Q_OBJECT + +public: + + explicit QOfonoConnectionContextInterface(const QString &dbusPathName, QObject *parent = 0); + ~QOfonoConnectionContextInterface(); + + QVariant getProperty(const QString &); + bool active(); + QString accessPointName(); + QString name(); + +Q_SIGNALS: +private: + QVariantMap getProperties(); + QVariantMap propertiesMap; +private slots: + void propertyChanged(const QString &, const QDBusVariant &value); +}; QT_END_NAMESPACE diff --git a/src/plugins/bearer/networkmanager/networkmanager.pro b/src/plugins/bearer/networkmanager/networkmanager.pro index 1ed9bfaa1b..b3a270615c 100644 --- a/src/plugins/bearer/networkmanager/networkmanager.pro +++ b/src/plugins/bearer/networkmanager/networkmanager.pro @@ -6,16 +6,16 @@ load(qt_plugin) QT = core network-private dbus -HEADERS += qnmdbushelper.h \ - qnetworkmanagerservice.h \ +HEADERS += qnetworkmanagerservice.h \ qnetworkmanagerengine.h \ + ../linux_common/qofonoservice_linux_p.h \ ../qnetworksession_impl.h \ ../qbearerengine_impl.h SOURCES += main.cpp \ - qnmdbushelper.cpp \ qnetworkmanagerservice.cpp \ qnetworkmanagerengine.cpp \ + ../linux_common/qofonoservice_linux.cpp \ ../qnetworksession_impl.cpp OTHER_FILES += networkmanager.json diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 5f49ea0b6d..f07d7b242b 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -47,6 +47,7 @@ #include #include #include +#include "../linux_common/qofonoservice_linux_p.h" #ifndef QT_NO_BEARERMANAGEMENT #ifndef QT_NO_DBUS @@ -57,44 +58,55 @@ QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) : QBearerEngineImpl(parent), managerInterface(new QNetworkManagerInterface(this)), systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE, this)), - userSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE, this)) + ofonoManager(new QOfonoManagerInterface(this)), + ofonoNetwork(0), + ofonoContextManager(0) { + if (!managerInterface->isValid()) return; - managerInterface->setConnections(); + qDBusRegisterMetaType(); + connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), this, SLOT(deviceAdded(QDBusObjectPath))); connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), this, SLOT(deviceRemoved(QDBusObjectPath))); connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), this, SLOT(activationFinished(QDBusPendingCallWatcher*))); - connect(managerInterface, SIGNAL(propertiesChanged(QString,QMap)), - this, SLOT(interfacePropertiesChanged(QString,QMap))); + connect(managerInterface, SIGNAL(propertiesChanged(QMap)), + this, SLOT(interfacePropertiesChanged(QMap))); + managerInterface->setConnections(); - qDBusRegisterMetaType(); - - systemSettings->setConnections(); connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), this, SLOT(newConnection(QDBusObjectPath))); - - userSettings->setConnections(); - connect(userSettings, SIGNAL(newConnection(QDBusObjectPath)), - this, SLOT(newConnection(QDBusObjectPath))); + systemSettings->setConnections(); } QNetworkManagerEngine::~QNetworkManagerEngine() { qDeleteAll(connections); + connections.clear(); qDeleteAll(accessPoints); + accessPoints.clear(); qDeleteAll(wirelessDevices); - qDeleteAll(activeConnections); + wirelessDevices.clear(); + qDeleteAll(activeConnectionsList); + activeConnectionsList.clear(); + qDeleteAll(interfaceDevices); + interfaceDevices.clear(); + + connectionInterfaces.clear(); } void QNetworkManagerEngine::initialize() { QMutexLocker locker(&mutex); + connect(ofonoManager,SIGNAL(modemChanged()),this,SLOT(changedModem())); + ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); + ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); + // Get current list of access points. foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { locker.unlock(); @@ -102,8 +114,24 @@ void QNetworkManagerEngine::initialize() locker.relock(); } - // Get connections. + // Get active connections. + foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { + QNetworkManagerConnectionActive *activeConnection = + new QNetworkManagerConnectionActive(acPath.path(),this); + activeConnectionsList.insert(acPath.path(), activeConnection); + connect(activeConnection, SIGNAL(propertiesChanged(QMap)), + this, SLOT(activeConnectionPropertiesChanged(QMap))); + activeConnection->setConnections(); + + QList devices = activeConnection->devices(); + if (!devices.isEmpty()) { + QNetworkManagerInterfaceDevice device(devices.at(0).path(),this); + connectionInterfaces.insert(activeConnection->connection().path(),device.networkInterface()); + } + } + + // Get connections. foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) { locker.unlock(); if (!hasIdentifier(settingsPath.path())) @@ -111,57 +139,19 @@ void QNetworkManagerEngine::initialize() locker.relock(); } - foreach (const QDBusObjectPath &settingsPath, userSettings->listConnections()) { - locker.unlock(); - if (!hasIdentifier(settingsPath.path())) - newConnection(settingsPath, userSettings); - locker.relock(); - } - - // Get active connections. - foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { - QNetworkManagerConnectionActive *activeConnection = - new QNetworkManagerConnectionActive(acPath.path(),this); - activeConnections.insert(acPath.path(), activeConnection); - - activeConnection->setConnections(); - connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap)), - this, SLOT(activeConnectionPropertiesChanged(QString,QMap))); - } Q_EMIT updateCompleted(); } bool QNetworkManagerEngine::networkManagerAvailable() const { - QMutexLocker locker(&mutex); - return managerInterface->isValid(); } -QString QNetworkManagerEngine::getInterfaceFromId(const QString &id) +QString QNetworkManagerEngine::getInterfaceFromId(const QString &settingsPath) { - QMutexLocker locker(&mutex); - - foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { - QNetworkManagerConnectionActive activeConnection(acPath.path()); - - const QString identifier = activeConnection.connection().path(); - - if (id == identifier) { - QList devices = activeConnection.devices(); - - if (devices.isEmpty()) - continue; - - QNetworkManagerInterfaceDevice device(devices.at(0).path()); - return device.networkInterface(); - } - } - - return QString(); + return connectionInterfaces.value(settingsPath); } - bool QNetworkManagerEngine::hasIdentifier(const QString &id) { QMutexLocker locker(&mutex); @@ -177,35 +167,34 @@ void QNetworkManagerEngine::connectToId(const QString &id) if (!connection) return; - QNmSettingsMap map = connection->getSettings(); - const QString connectionType = map.value("connection").value("type").toString(); + NMDeviceType connectionType = connection->getType(); QString dbusDevicePath; - foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { - QNetworkManagerInterfaceDevice device(devicePath.path()); - if (device.deviceType() == DEVICE_TYPE_ETHERNET && - connectionType == QLatin1String("802-3-ethernet")) { - dbusDevicePath = devicePath.path(); + const QString settingsPath = connection->connectionInterface()->path(); + QString specificPath = configuredAccessPoints.key(settingsPath); + + QHashIterator i(interfaceDevices); + while (i.hasNext()) { + i.next(); + if (i.value()->deviceType() == DEVICE_TYPE_ETHERNET && + connectionType == DEVICE_TYPE_ETHERNET) { + dbusDevicePath = i.key(); break; - } else if (device.deviceType() == DEVICE_TYPE_WIFI && - connectionType == QLatin1String("802-11-wireless")) { - dbusDevicePath = devicePath.path(); + } else if (i.value()->deviceType() == DEVICE_TYPE_WIFI && + connectionType == DEVICE_TYPE_WIFI) { + dbusDevicePath = i.key(); break; - } else if (device.deviceType() == DEVICE_TYPE_MODEM && - connectionType == QLatin1String("gsm")) { - dbusDevicePath = devicePath.path(); + } else if (i.value()->deviceType() == DEVICE_TYPE_MODEM && + connectionType == DEVICE_TYPE_MODEM) { + dbusDevicePath = i.key(); break; } } - const QString service = connection->connectionInterface()->service(); - const QString settingsPath = connection->connectionInterface()->path(); - QString specificPath = configuredAccessPoints.key(settingsPath); - if (specificPath.isEmpty()) specificPath = "/"; - managerInterface->activateConnection(service, QDBusObjectPath(settingsPath), + managerInterface->activateConnection(QDBusObjectPath(settingsPath), QDBusObjectPath(dbusDevicePath), QDBusObjectPath(specificPath)); } @@ -221,13 +210,11 @@ void QNetworkManagerEngine::disconnectFromId(const QString &id) return; } - foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { - QNetworkManagerConnectionActive activeConnection(acPath.path()); - - const QString identifier = activeConnection.connection().path(); - - if (id == identifier && accessPointConfigurations.contains(id)) { - managerInterface->deactivateConnection(acPath); + QHashIterator i(activeConnectionsList); + while (i.hasNext()) { + i.next(); + if (id == i.value()->connection().path() && accessPointConfigurations.contains(id)) { + managerInterface->deactivateConnection(QDBusObjectPath(i.key())); break; } } @@ -250,12 +237,9 @@ void QNetworkManagerEngine::scanFinished() QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection); } -void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, - const QMap &properties) +void QNetworkManagerEngine::interfacePropertiesChanged(const QMap &properties) { - Q_UNUSED(path) QMutexLocker locker(&mutex); - QMapIterator i(properties); while (i.hasNext()) { i.next(); @@ -267,22 +251,20 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, qdbus_cast >(i.value().value()); QStringList identifiers = accessPointConfigurations.keys(); - foreach (const QString &id, identifiers) - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); - - QStringList priorActiveConnections = this->activeConnections.keys(); + QStringList priorActiveConnections = activeConnectionsList.keys(); foreach (const QDBusObjectPath &acPath, activeConnections) { priorActiveConnections.removeOne(acPath.path()); QNetworkManagerConnectionActive *activeConnection = - this->activeConnections.value(acPath.path()); + activeConnectionsList.value(acPath.path()); + if (!activeConnection) { activeConnection = new QNetworkManagerConnectionActive(acPath.path(),this); - this->activeConnections.insert(acPath.path(), activeConnection); + activeConnectionsList.insert(acPath.path(), activeConnection); + connect(activeConnection, SIGNAL(propertiesChanged(QMap)), + this, SLOT(activeConnectionPropertiesChanged(QMap))); activeConnection->setConnections(); - connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap)), - this, SLOT(activeConnectionPropertiesChanged(QString,QMap))); } const QString id = activeConnection->connection().path(); @@ -295,6 +277,11 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && ptr->state != QNetworkConfiguration::Active) { ptr->state = QNetworkConfiguration::Active; + + if (activeConnectionsList.value(id) && activeConnectionsList.value(id)->defaultRoute() + && managerInterface->state() < QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL) { + ptr->purpose = QNetworkConfiguration::PrivatePurpose; + } ptr->mutex.unlock(); locker.unlock(); @@ -307,7 +294,7 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, } while (!priorActiveConnections.isEmpty()) - delete this->activeConnections.take(priorActiveConnections.takeFirst()); + delete activeConnectionsList.take(priorActiveConnections.takeFirst()); while (!identifiers.isEmpty()) { QNetworkConfigurationPrivatePointer ptr = @@ -330,14 +317,13 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, } } -void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QString &path, - const QMap &properties) +void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMap &properties) { QMutexLocker locker(&mutex); Q_UNUSED(properties) - QNetworkManagerConnectionActive *activeConnection = activeConnections.value(path); + QNetworkManagerConnectionActive *activeConnection = qobject_cast(sender()); if (!activeConnection) return; @@ -347,8 +333,13 @@ void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QString &pat QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); if (ptr) { ptr->mutex.lock(); - if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && - ptr->state != QNetworkConfiguration::Active) { + if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + QList devices = activeConnection->devices(); + if (!devices.isEmpty()) { + QNetworkManagerInterfaceDevice device(devices.at(0).path(),this); + connectionInterfaces.insert(id,device.networkInterface()); + } + ptr->state |= QNetworkConfiguration::Active; ptr->mutex.unlock(); @@ -356,22 +347,17 @@ void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QString &pat emit configurationChanged(ptr); locker.relock(); } else { + connectionInterfaces.remove(id); ptr->mutex.unlock(); } } } -void QNetworkManagerEngine::devicePropertiesChanged(const QString &/*path*/,quint32 /*state*/) -{ -// Q_UNUSED(path); -// Q_UNUSED(state) -} - -void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &activeConnectionsList) +void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &connectionsList) { QMutexLocker locker(&mutex); for (int i = 0; i < connections.count(); ++i) { - if (activeConnectionsList.contains(connections.at(i)->connectionInterface()->path())) + if (connectionsList.contains(connections.at(i)->connectionInterface()->path())) continue; const QString settingsPath = connections.at(i)->connectionInterface()->path(); @@ -392,27 +378,23 @@ void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &activeCo void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) { - QMutexLocker locker(&mutex); QNetworkManagerInterfaceDevice *iDevice; iDevice = new QNetworkManagerInterfaceDevice(path.path(),this); connect(iDevice,SIGNAL(connectionsChanged(QStringList)), this,SLOT(deviceConnectionsChanged(QStringList))); - connect(iDevice,SIGNAL(stateChanged(QString,quint32)), - this,SLOT(devicePropertiesChanged(QString,quint32))); iDevice->setConnections(); interfaceDevices.insert(path.path(),iDevice); - if (iDevice->deviceType() == DEVICE_TYPE_WIFI) { QNetworkManagerInterfaceDeviceWireless *wirelessDevice = new QNetworkManagerInterfaceDeviceWireless(iDevice->connectionInterface()->path(),this); - wirelessDevice->setConnections(); connect(wirelessDevice, SIGNAL(accessPointAdded(QString)), this, SLOT(newAccessPoint(QString))); connect(wirelessDevice, SIGNAL(accessPointRemoved(QString)), this, SLOT(removeAccessPoint(QString))); connect(wirelessDevice,SIGNAL(scanDone()),this,SLOT(scanFinished())); + wirelessDevice->setConnections(); foreach (const QDBusObjectPath &apPath, wirelessDevice->getAccessPoints()) newAccessPoint(apPath.path()); @@ -444,10 +426,10 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, if (!settings) settings = qobject_cast(sender()); - if (!settings) + if (!settings) { return; + } - settings->deleteLater(); QNetworkManagerSettingsConnection *connection = new QNetworkManagerSettingsConnection(settings->connectionInterface()->service(), path.path(),this); @@ -482,12 +464,10 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, parseConnection(settingsPath, connection->getSettings()); // Check if connection is active. - foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { - QNetworkManagerConnectionActive activeConnection(acPath.path()); - - if (activeConnection.defaultRoute() && - activeConnection.connection().path() == settingsPath && - activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + QHashIterator i(activeConnectionsList); + while (i.hasNext()) { + i.next(); + if (i.value()->connection().path() == settingsPath) { cpPriv->state |= QNetworkConfiguration::Active; break; } @@ -505,6 +485,7 @@ void QNetworkManagerEngine::removeConnection(const QString &path) QNetworkManagerSettingsConnection *connection = qobject_cast(sender()); + if (!connection) return; @@ -525,6 +506,7 @@ void QNetworkManagerEngine::removeConnection(const QString &path) while (i.hasNext()) { i.next(); if (i.value() == path) { + configuredAccessPoints.remove(i.key()); newAccessPoint(i.key()); } } @@ -575,10 +557,9 @@ void QNetworkManagerEngine::updateConnection() void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) { QMutexLocker locker(&mutex); - + QDBusPendingReply reply(*watcher); watcher->deleteLater(); - QDBusPendingReply reply(*watcher); if (!reply.isError()) { QDBusObjectPath result = reply.value(); @@ -620,15 +601,14 @@ void QNetworkManagerEngine::newAccessPoint(const QString &path) if (okToAdd) { accessPoints.append(accessPoint); accessPoint->setConnections(); - connect(accessPoint, SIGNAL(propertiesChanged(QMap)), - this, SLOT(updateAccessPoint(QMap))); } - // Check if configuration exists for connection. if (!accessPoint->ssid().isEmpty()) { + for (int i = 0; i < connections.count(); ++i) { QNetworkManagerSettingsConnection *connection = connections.at(i); const QString settingsPath = connection->connectionInterface()->path(); + if (accessPoint->ssid() == connection->getSsid()) { if (!configuredAccessPoints.contains(path)) { configuredAccessPoints.insert(path,settingsPath); @@ -655,11 +635,7 @@ void QNetworkManagerEngine::newAccessPoint(const QString &path) ptr->isValid = true; ptr->id = path; ptr->type = QNetworkConfiguration::InternetAccessPoint; - if (accessPoint->flags() == NM_802_11_AP_FLAGS_PRIVACY) { - ptr->purpose = QNetworkConfiguration::PrivatePurpose; - } else { - ptr->purpose = QNetworkConfiguration::PublicPurpose; - } + ptr->purpose = QNetworkConfiguration::PublicPurpose; ptr->state = QNetworkConfiguration::Undefined; ptr->bearerType = QNetworkConfiguration::BearerWLAN; @@ -674,13 +650,13 @@ void QNetworkManagerEngine::removeAccessPoint(const QString &path) QMutexLocker locker(&mutex); for (int i = 0; i < accessPoints.count(); ++i) { QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); - if (accessPoint->connectionInterface()->path() == path) { accessPoints.removeOne(accessPoint); if (configuredAccessPoints.contains(accessPoint->connectionInterface()->path())) { // find connection and change state to Defined configuredAccessPoints.remove(accessPoint->connectionInterface()->path()); + for (int i = 0; i < connections.count(); ++i) { QNetworkManagerSettingsConnection *connection = connections.at(i); @@ -705,8 +681,6 @@ void QNetworkManagerEngine::removeAccessPoint(const QString &path) accessPointConfigurations.take(path); if (ptr) { - locker.unlock(); - locker.unlock(); emit configurationRemoved(ptr); locker.relock(); @@ -718,42 +692,9 @@ void QNetworkManagerEngine::removeAccessPoint(const QString &path) } } -void QNetworkManagerEngine::updateAccessPoint(const QMap &map) -{ - QMutexLocker locker(&mutex); - - Q_UNUSED(map) - - QNetworkManagerInterfaceAccessPoint *accessPoint = - qobject_cast(sender()); - if (!accessPoint) - return; - accessPoint->deleteLater(); - for (int i = 0; i < connections.count(); ++i) { - QNetworkManagerSettingsConnection *connection = connections.at(i); - - if (accessPoint->ssid() == connection->getSsid()) { - const QString settingsPath = connection->connectionInterface()->path(); - const QString connectionId = settingsPath; - - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.value(connectionId); - ptr->mutex.lock(); - QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; - ptr->state = (flag | QNetworkConfiguration::Discovered); - ptr->mutex.unlock(); - - locker.unlock(); - emit configurationChanged(ptr); - return; - } - } -} - QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &settingsPath, const QNmSettingsMap &map) { - // Q_UNUSED(service); QMutexLocker locker(&mutex); QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; cpPriv->name = map.value("connection").value("id").toString(); @@ -765,17 +706,15 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri cpPriv->purpose = QNetworkConfiguration::PublicPurpose; cpPriv->state = QNetworkConfiguration::Defined; - const QString connectionType = map.value("connection").value("type").toString(); if (connectionType == QLatin1String("802-3-ethernet")) { cpPriv->bearerType = QNetworkConfiguration::BearerEthernet; - cpPriv->purpose = QNetworkConfiguration::PublicPurpose; foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { - QNetworkManagerInterfaceDevice device(devicePath.path()); + QNetworkManagerInterfaceDevice device(devicePath.path(),this); if (device.deviceType() == DEVICE_TYPE_ETHERNET) { - QNetworkManagerInterfaceDeviceWired wiredDevice(device.connectionInterface()->path()); + QNetworkManagerInterfaceDeviceWired wiredDevice(device.connectionInterface()->path(),this); if (wiredDevice.carrier()) { cpPriv->state |= QNetworkConfiguration::Discovered; break; @@ -786,12 +725,6 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri cpPriv->bearerType = QNetworkConfiguration::BearerWLAN; const QString connectionSsid = map.value("802-11-wireless").value("ssid").toString(); - const QString connectionSecurity = map.value("802-11-wireless").value("security").toString(); - if (!connectionSecurity.isEmpty()) { - cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; - } else { - cpPriv->purpose = QNetworkConfiguration::PublicPurpose; - } for (int i = 0; i < accessPoints.count(); ++i) { if (connectionSsid == accessPoints.at(i)->ssid() && map.value("802-11-wireless").value("seen-bssids").toStringList().contains(accessPoints.at(i)->hwAddress())) { @@ -813,31 +746,11 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri } } } else if (connectionType == QLatin1String("gsm")) { - - foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { - QNetworkManagerInterfaceDevice device(devicePath.path()); - - if (device.deviceType() == DEVICE_TYPE_MODEM) { - QNetworkManagerInterfaceDeviceModem deviceModem(device.connectionInterface()->path(),this); - switch (deviceModem.currentCapabilities()) { - case 2: - cpPriv->bearerType = QNetworkConfiguration::Bearer2G; - break; - case 4: - cpPriv->bearerType = QNetworkConfiguration::Bearer3G; - break; - case 8: - cpPriv->bearerType = QNetworkConfiguration::Bearer4G; - break; - default: - cpPriv->bearerType = QNetworkConfiguration::BearerUnknown; - break; - }; - } + cpPriv->bearerType = currentBearerType(); + if (map.value("connection").contains("timestamp")) { + cpPriv->state |= QNetworkConfiguration::Discovered; } - - cpPriv->purpose = QNetworkConfiguration::PrivatePurpose; - cpPriv->state |= QNetworkConfiguration::Discovered; + cpPriv->name = contextName(map.value("connection").value("id").toString()); } return cpPriv; @@ -857,7 +770,6 @@ QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &id) { QMutexLocker locker(&mutex); - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); if (!ptr) @@ -866,8 +778,8 @@ QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &i if (!ptr->isValid) return QNetworkSession::Invalid; - foreach (const QString &acPath, activeConnections.keys()) { - QNetworkManagerConnectionActive *activeConnection = activeConnections.value(acPath); + foreach (const QString &acPath, activeConnectionsList.keys()) { + QNetworkManagerConnectionActive *activeConnection = activeConnectionsList.value(acPath); const QString identifier = activeConnection->connection().path(); @@ -899,7 +811,7 @@ quint64 QNetworkManagerEngine::bytesWritten(const QString &id) QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { - const QString networkInterface = getInterfaceFromId(id); + const QString networkInterface = connectionInterfaces.value(id); if (!networkInterface.isEmpty()) { const QString devFile = QLatin1String("/sys/class/net/") + networkInterface + @@ -927,7 +839,7 @@ quint64 QNetworkManagerEngine::bytesReceived(const QString &id) QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { - const QString networkInterface = getInterfaceFromId(id); + const QString networkInterface = connectionInterfaces.value(id); if (!networkInterface.isEmpty()) { const QString devFile = QLatin1String("/sys/class/net/") + networkInterface + @@ -977,6 +889,54 @@ QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration( return QNetworkConfigurationPrivatePointer(); } +void QNetworkManagerEngine::changedModem() +{ + if (ofonoNetwork) + delete ofonoNetwork; + + ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); + + if (ofonoContextManager) + delete ofonoContextManager; + ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); +} + +QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType() +{ + if (ofonoContextManager) { + QString bearer = ofonoContextManager->bearer(); + if (bearer == QLatin1String("gsm")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QLatin1String("edge")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QLatin1String("umts")) { + return QNetworkConfiguration::BearerWCDMA; + } else if (bearer == QLatin1String("hspa") + || bearer == QLatin1String("hsdpa") + || bearer == QLatin1String("hsupa")) { + return QNetworkConfiguration::BearerHSPA; + } else if (bearer == QLatin1String("lte")) { + return QNetworkConfiguration::BearerLTE; + } + } + return QNetworkConfiguration::BearerUnknown; +} + +QString QNetworkManagerEngine::contextName(const QString &path) +{ + if (ofonoContextManager) { + QString contextPart = path.section('/', -1); + + Q_FOREACH (const QString &oContext, ofonoContextManager->contexts()) { + if (oContext.contains(contextPart)) { + QOfonoConnectionContextInterface contextInterface(oContext,this); + return contextInterface.name(); + } + } + } + return path; +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index ab1cfea71e..d2ef9886a3 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -49,6 +49,8 @@ #include "qnetworkmanagerservice.h" +#include "../linux_common/qofonoservice_linux_p.h" + #include #include @@ -89,11 +91,8 @@ public: QNetworkConfigurationPrivatePointer defaultConfiguration(); private Q_SLOTS: - void interfacePropertiesChanged(const QString &path, - const QMap &properties); - void activeConnectionPropertiesChanged(const QString &path, - const QMap &properties); - void devicePropertiesChanged(const QString &path, quint32); + void interfacePropertiesChanged(const QMap &properties); + void activeConnectionPropertiesChanged(const QMap &properties); void deviceAdded(const QDBusObjectPath &path); void deviceRemoved(const QDBusObjectPath &path); @@ -106,8 +105,8 @@ private Q_SLOTS: void newAccessPoint(const QString &path); void removeAccessPoint(const QString &path); - void updateAccessPoint(const QMap &map); void scanFinished(); + void changedModem(); private: QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath, @@ -116,14 +115,21 @@ private: QNetworkManagerInterface *managerInterface; QNetworkManagerSettings *systemSettings; - QNetworkManagerSettings *userSettings; QHash wirelessDevices; - QHash activeConnections; + QHash activeConnectionsList; QList connections; QList accessPoints; QHash interfaceDevices; QMap configuredAccessPoints; //ap, settings path + QHash connectionInterfaces; // ac, interface + + QOfonoManagerInterface *ofonoManager; + QOfonoNetworkRegistrationInterface *ofonoNetwork; + QOfonoDataConnectionManagerInterface *ofonoContextManager; + QNetworkConfiguration::BearerType currentBearerType(); + QString contextName(const QString &path); + }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index f249ac6100..2d54fa3029 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -44,7 +44,6 @@ #include #include "qnetworkmanagerservice.h" -#include "qnmdbushelper.h" #ifndef QT_NO_DBUS @@ -64,18 +63,38 @@ QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent) d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), QLatin1String(NM_DBUS_INTERFACE), - QDBusConnection::systemBus()); + QDBusConnection::systemBus(),parent); if (!d->connectionInterface->isValid()) { d->valid = false; return; } d->valid = true; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - connect(nmDBusHelper,SIGNAL(pathForStateChanged(QString,quint32)), - this, SIGNAL(stateChanged(QString,quint32))); + QDBusInterface managerPropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus()); + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE); + QDBusPendingReply propsReply + = managerPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusPendingReply > nmReply + = d->connectionInterface->call(QLatin1String("GetDevices")); + nmReply.waitForFinished(); + if (!nmReply.isError()) { + devicesPathList = nmReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + QLatin1String(NM_DBUS_PATH), + QLatin1String(NM_DBUS_INTERFACE), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); } QNetworkManagerInterface::~QNetworkManagerInterface() @@ -91,27 +110,24 @@ bool QNetworkManagerInterface::isValid() bool QNetworkManagerInterface::setConnections() { - if(!isValid() ) + if (!isValid()) return false; - QDBusConnection dbusConnection = QDBusConnection::systemBus(); - - bool allOk = false; - if (dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), QLatin1String(NM_DBUS_INTERFACE), QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotPropertiesChanged(QMap)))) { - allOk = true; - } - if (dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + this,SLOT(propertiesSwap(QMap))); + + bool allOk = false; + if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), QLatin1String(NM_DBUS_INTERFACE), QLatin1String("DeviceAdded"), this,SIGNAL(deviceAdded(QDBusObjectPath)))) { allOk = true; } - if (dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), + if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), QLatin1String(NM_DBUS_PATH), QLatin1String(NM_DBUS_INTERFACE), QLatin1String("DeviceRemoved"), @@ -127,14 +143,17 @@ QDBusInterface *QNetworkManagerInterface::connectionInterface() const return d->connectionInterface; } -QList QNetworkManagerInterface::getDevices() const +QList QNetworkManagerInterface::getDevices() { - QDBusReply > reply = d->connectionInterface->call(QLatin1String("GetDevices")); - return reply.value(); + if (devicesPathList.isEmpty()) { + qWarning() << "using blocking call!"; + QDBusReply > reply = d->connectionInterface->call(QLatin1String("GetDevices")); + devicesPathList = reply.value(); + } + return devicesPathList; } -void QNetworkManagerInterface::activateConnection( const QString &, - QDBusObjectPath connectionPath, +void QNetworkManagerInterface::activateConnection(QDBusObjectPath connectionPath, QDBusObjectPath devicePath, QDBusObjectPath specificObject) { @@ -150,28 +169,80 @@ void QNetworkManagerInterface::activateConnection( const QString &, void QNetworkManagerInterface::deactivateConnection(QDBusObjectPath connectionPath) const { - d->connectionInterface->call(QLatin1String("DeactivateConnection"), QVariant::fromValue(connectionPath)); + d->connectionInterface->asyncCall(QLatin1String("DeactivateConnection"), QVariant::fromValue(connectionPath)); } bool QNetworkManagerInterface::wirelessEnabled() const { - return d->connectionInterface->property("WirelessEnabled").toBool(); + if (propertyMap.contains("WirelessEnabled")) + return propertyMap.value("WirelessEnabled").toBool(); + return false; } bool QNetworkManagerInterface::wirelessHardwareEnabled() const { - return d->connectionInterface->property("WirelessHardwareEnabled").toBool(); + if (propertyMap.contains("WirelessHardwareEnabled")) + return propertyMap.value("WirelessHardwareEnabled").toBool(); + return false; } QList QNetworkManagerInterface::activeConnections() const { - QVariant prop = d->connectionInterface->property("ActiveConnections"); - return prop.value >(); + if (propertyMap.contains("ActiveConnections")) { + + const QDBusArgument &dbusArgs = propertyMap.value("ActiveConnections").value(); + QDBusObjectPath path; + QList list; + + dbusArgs.beginArray(); + while (!dbusArgs.atEnd()) { + dbusArgs >> path; + list.append(path); + } + dbusArgs.endArray(); + + return list; + } + + QList list; + list << QDBusObjectPath(); + return list; } -quint32 QNetworkManagerInterface::state() +QNetworkManagerInterface::NMState QNetworkManagerInterface::state() { - return d->connectionInterface->property("State").toUInt(); + if (propertyMap.contains("State")) + return static_cast(propertyMap.value("State").toUInt()); + return QNetworkManagerInterface::NM_STATE_UNKNOWN; +} + +QString QNetworkManagerInterface::version() const +{ + if (propertyMap.contains("Version")) + return propertyMap.value("Version").toString(); + return QString(); +} + +void QNetworkManagerInterface::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + + if (i.key() == QStringLiteral("State")) { + quint32 state = i.value().toUInt(); + if (state == NM_DEVICE_STATE_ACTIVATED + || state == NM_DEVICE_STATE_DISCONNECTED + || state == NM_DEVICE_STATE_UNAVAILABLE + || state == NM_DEVICE_STATE_FAILED) { + Q_EMIT propertiesChanged(map); + Q_EMIT stateChanged(state); + } + } else if (i.key() == QStringLiteral("ActiveConnections")) { + Q_EMIT propertiesChanged(map); + } + } } class QNetworkManagerInterfaceAccessPointPrivate @@ -183,18 +254,38 @@ public: }; QNetworkManagerInterfaceAccessPoint::QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { d = new QNetworkManagerInterfaceAccessPointPrivate(); d->path = dbusPathName; d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), d->path, QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), - QDBusConnection::systemBus()); + QDBusConnection::systemBus(),parent); if (!d->connectionInterface->isValid()) { d->valid = false; return; } + QDBusInterface accessPointPropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus()); + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT); + QDBusPendingReply propsReply + = accessPointPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); + d->valid = true; } @@ -212,24 +303,10 @@ bool QNetworkManagerInterfaceAccessPoint::isValid() bool QNetworkManagerInterfaceAccessPoint::setConnections() { - if(!isValid() ) + if (!isValid()) return false; - bool allOk = false; - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - - if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotPropertiesChanged(QMap))) ) { - allOk = true; - - } - return allOk; + return true; } QDBusInterface *QNetworkManagerInterfaceAccessPoint::connectionInterface() const @@ -239,47 +316,74 @@ QDBusInterface *QNetworkManagerInterfaceAccessPoint::connectionInterface() const quint32 QNetworkManagerInterfaceAccessPoint::flags() const { - return d->connectionInterface->property("Flags").toUInt(); + if (propertyMap.contains("Flags")) + return propertyMap.value("Flags").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceAccessPoint::wpaFlags() const { - return d->connectionInterface->property("WpaFlags").toUInt(); + if (propertyMap.contains("WpaFlags")) + return propertyMap.value("WpaFlags").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceAccessPoint::rsnFlags() const { - return d->connectionInterface->property("RsnFlags").toUInt(); + if (propertyMap.contains("RsnFlags")) + return propertyMap.value("RsnFlags").toUInt(); + return 0; } QString QNetworkManagerInterfaceAccessPoint::ssid() const { - return d->connectionInterface->property("Ssid").toString(); + if (propertyMap.contains("Ssid")) + return propertyMap.value("Ssid").toString(); + return QString(); } quint32 QNetworkManagerInterfaceAccessPoint::frequency() const { - return d->connectionInterface->property("Frequency").toUInt(); + if (propertyMap.contains("Frequency")) + return propertyMap.value("Frequency").toUInt(); + return 0; } QString QNetworkManagerInterfaceAccessPoint::hwAddress() const { - return d->connectionInterface->property("HwAddress").toString(); + if (propertyMap.contains("HwAddress")) + return propertyMap.value("HwAddress").toString(); + return QString(); } quint32 QNetworkManagerInterfaceAccessPoint::mode() const { - return d->connectionInterface->property("Mode").toUInt(); + if (propertyMap.contains("Mode")) + return propertyMap.value("Mode").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceAccessPoint::maxBitrate() const { - return d->connectionInterface->property("MaxBitrate").toUInt(); + if (propertyMap.contains("MaxBitrate")) + return propertyMap.value("MaxBitrate").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceAccessPoint::strength() const { - return d->connectionInterface->property("Strength").toUInt(); + if (propertyMap.contains("Strength")) + return propertyMap.value("Strength").toUInt(); + return 0; +} + +void QNetworkManagerInterfaceAccessPoint::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + } } class QNetworkManagerInterfaceDevicePrivate @@ -291,18 +395,39 @@ public: }; QNetworkManagerInterfaceDevice::QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { + d = new QNetworkManagerInterfaceDevicePrivate(); d->path = deviceObjectPath; d->connectionInterface = new QDBusInterface(QLatin1String(NM_DBUS_SERVICE), d->path, QLatin1String(NM_DBUS_INTERFACE_DEVICE), - QDBusConnection::systemBus()); + QDBusConnection::systemBus(),parent); if (!d->connectionInterface->isValid()) { d->valid = false; return; } + QDBusInterface devicePropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus(),parent); + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE); + QDBusPendingReply propsReply + = devicePropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); d->valid = true; } @@ -319,35 +444,10 @@ bool QNetworkManagerInterfaceDevice::isValid() bool QNetworkManagerInterfaceDevice::setConnections() { - if(!isValid() ) + if (!isValid()) return false; - bool allOk = true; - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper,SIGNAL(pathForStateChanged(QString,quint32)), - this, SIGNAL(stateChanged(QString,quint32))); - - if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_DEVICE), - QLatin1String("StateChanged"), - nmDBusHelper,SLOT(deviceStateChanged(quint32)))) { - allOk = false; - } - - connect(nmDBusHelper, SIGNAL(pathForConnectionsChanged(QStringList)), - this,SIGNAL(connectionsChanged(QStringList))); - - if (QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_ACCESS_POINT), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotPropertiesChanged(QMap))) ) { - allOk = false; - } - - return allOk; + return true; } QDBusInterface *QNetworkManagerInterfaceDevice::connectionInterface() const @@ -357,33 +457,66 @@ QDBusInterface *QNetworkManagerInterfaceDevice::connectionInterface() const QString QNetworkManagerInterfaceDevice::udi() const { - return d->connectionInterface->property("Udi").toString(); + if (propertyMap.contains("Udi")) + return propertyMap.value("Udi").toString(); + return QString(); } QString QNetworkManagerInterfaceDevice::networkInterface() const { - return d->connectionInterface->property("Interface").toString(); + if (propertyMap.contains("Interface")) + return propertyMap.value("Interface").toString(); + return QString(); } quint32 QNetworkManagerInterfaceDevice::ip4Address() const { - return d->connectionInterface->property("Ip4Address").toUInt(); + if (propertyMap.contains("Ip4Address")) + return propertyMap.value("Ip4Address").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceDevice::state() const { - return d->connectionInterface->property("State").toUInt(); + if (propertyMap.contains("State")) + return propertyMap.value("State").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceDevice::deviceType() const { - return d->connectionInterface->property("DeviceType").toUInt(); + if (propertyMap.contains("DeviceType")) + return propertyMap.value("DeviceType").toUInt(); + return 0; } QDBusObjectPath QNetworkManagerInterfaceDevice::ip4config() const { - QVariant prop = d->connectionInterface->property("Ip4Config"); - return prop.value(); + if (propertyMap.contains("Ip4Config")) + return propertyMap.value("Ip4Config").value(); + return QDBusObjectPath(); +} + +void QNetworkManagerInterfaceDevice::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + if (i.key() == QStringLiteral("AvailableConnections")) { //Device + const QDBusArgument &dbusArgs = i.value().value(); + QDBusObjectPath path; + QStringList paths; + dbusArgs.beginArray(); + while (!dbusArgs.atEnd()) { + dbusArgs >> path; + paths << path.path(); + } + dbusArgs.endArray(); + Q_EMIT connectionsChanged(paths); + } + propertyMap.insert(i.key(),i.value()); + } + Q_EMIT propertiesChanged(map); } class QNetworkManagerInterfaceDeviceWiredPrivate @@ -395,7 +528,7 @@ public: }; QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { d = new QNetworkManagerInterfaceDeviceWiredPrivate(); d->path = ifaceDevicePath; @@ -407,6 +540,27 @@ QNetworkManagerInterfaceDeviceWired::QNetworkManagerInterfaceDeviceWired(const Q d->valid = false; return; } + QDBusInterface deviceWiredPropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus(),parent); + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED); + QDBusPendingReply propsReply + = deviceWiredPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); + d->valid = true; } @@ -424,23 +578,9 @@ bool QNetworkManagerInterfaceDeviceWired::isValid() bool QNetworkManagerInterfaceDeviceWired::setConnections() { - if(!isValid() ) + if (!isValid()) return false; - - bool allOk = true; - - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - if (!QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRED), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotPropertiesChanged(QMap))) ) { - allOk = false; - } - return allOk; + return true; } QDBusInterface *QNetworkManagerInterfaceDeviceWired::connectionInterface() const @@ -450,17 +590,33 @@ QDBusInterface *QNetworkManagerInterfaceDeviceWired::connectionInterface() const QString QNetworkManagerInterfaceDeviceWired::hwAddress() const { - return d->connectionInterface->property("HwAddress").toString(); + if (propertyMap.contains("HwAddress")) + return propertyMap.value("HwAddress").toString(); + return QString(); } quint32 QNetworkManagerInterfaceDeviceWired::speed() const { - return d->connectionInterface->property("Speed").toUInt(); + if (propertyMap.contains("Speed")) + return propertyMap.value("Speed").toUInt(); + return 0; } bool QNetworkManagerInterfaceDeviceWired::carrier() const { - return d->connectionInterface->property("Carrier").toBool(); + if (propertyMap.contains("Carrier")) + return propertyMap.value("Carrier").toBool(); + return false; +} + +void QNetworkManagerInterfaceDeviceWired::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + } + Q_EMIT propertiesChanged(map); } class QNetworkManagerInterfaceDeviceWirelessPrivate @@ -472,7 +628,7 @@ public: }; QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { d = new QNetworkManagerInterfaceDeviceWirelessPrivate(); d->path = ifaceDevicePath; @@ -484,6 +640,34 @@ QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(c d->valid = false; return; } + + + QDBusPendingReply > nmReply + = d->connectionInterface->call(QLatin1String("GetAccessPoints")); + + if (!nmReply.isError()) { + accessPointsList = nmReply.value(); + } + + QDBusInterface deviceWirelessPropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus(),parent); + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS); + QDBusPendingReply propsReply + = deviceWirelessPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); d->valid = true; } @@ -498,29 +682,31 @@ bool QNetworkManagerInterfaceDeviceWireless::isValid() return d->valid; } +void QNetworkManagerInterfaceDeviceWireless::slotAccessPointAdded(QDBusObjectPath path) +{ + if (path.path().length() > 2) + Q_EMIT accessPointAdded(path.path()); +} + +void QNetworkManagerInterfaceDeviceWireless::slotAccessPointRemoved(QDBusObjectPath path) +{ + if (path.path().length() > 2) + Q_EMIT accessPointRemoved(path.path()); +} + bool QNetworkManagerInterfaceDeviceWireless::setConnections() { - if(!isValid() ) + if (!isValid()) return false; QDBusConnection dbusConnection = QDBusConnection::systemBus(); bool allOk = true; - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - - connect(nmDBusHelper, SIGNAL(pathForAccessPointAdded(QString)), - this,SIGNAL(accessPointAdded(QString))); - - connect(nmDBusHelper, SIGNAL(pathForAccessPointRemoved(QString)), - this,SIGNAL(accessPointRemoved(QString))); if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), - d->path, + d->path, QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), QLatin1String("AccessPointAdded"), - nmDBusHelper, SLOT(slotAccessPointAdded(QDBusObjectPath)))) { + this, SLOT(slotAccessPointAdded(QDBusObjectPath)))) { allOk = false; } @@ -529,18 +715,10 @@ bool QNetworkManagerInterfaceDeviceWireless::setConnections() d->path, QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), QLatin1String("AccessPointRemoved"), - nmDBusHelper, SLOT(slotAccessPointRemoved(QDBusObjectPath)))) { + this, SLOT(slotAccessPointRemoved(QDBusObjectPath)))) { allOk = false; } - - if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotPropertiesChanged(QMap)))) { - allOk = false; - } if (!dbusConnection.connect(QLatin1String(NM_DBUS_SERVICE), d->path, QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), @@ -558,33 +736,48 @@ QDBusInterface *QNetworkManagerInterfaceDeviceWireless::connectionInterface() co QList QNetworkManagerInterfaceDeviceWireless::getAccessPoints() { - QDBusReply > reply = d->connectionInterface->call(QLatin1String("GetAccessPoints")); - return reply.value(); + if (accessPointsList.isEmpty()) { + qWarning() << "Using blocking call!"; + QDBusReply > reply + = d->connectionInterface->call(QLatin1String("GetAccessPoints")); + accessPointsList = reply.value(); + } + return accessPointsList; } QString QNetworkManagerInterfaceDeviceWireless::hwAddress() const { - return d->connectionInterface->property("HwAddress").toString(); + if (propertyMap.contains("HwAddress")) + return propertyMap.value("HwAddress").toString(); + return QString(); } quint32 QNetworkManagerInterfaceDeviceWireless::mode() const { - return d->connectionInterface->property("Mode").toUInt(); + if (propertyMap.contains("Mode")) + return propertyMap.value("Mode").toUInt(); + return 0; } quint32 QNetworkManagerInterfaceDeviceWireless::bitrate() const { - return d->connectionInterface->property("Bitrate").toUInt(); + if (propertyMap.contains("Bitrate")) + return propertyMap.value("Bitrate").toUInt(); + return 0; } QDBusObjectPath QNetworkManagerInterfaceDeviceWireless::activeAccessPoint() const { - return d->connectionInterface->property("ActiveAccessPoint").value(); + if (propertyMap.contains("ActiveAccessPoint")) + return propertyMap.value("ActiveAccessPoint").value(); + return QDBusObjectPath(); } quint32 QNetworkManagerInterfaceDeviceWireless::wirelessCapabilities() const { - return d->connectionInterface->property("WirelelessCapabilities").toUInt(); + if (propertyMap.contains("WirelelessCapabilities")) + return propertyMap.value("WirelelessCapabilities").toUInt(); + return 0; } void QNetworkManagerInterfaceDeviceWireless::scanIsDone() @@ -597,6 +790,17 @@ void QNetworkManagerInterfaceDeviceWireless::requestScan() d->connectionInterface->asyncCall(QLatin1String("RequestScan")); } +void QNetworkManagerInterfaceDeviceWireless::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + if (i.key() == QStringLiteral("ActiveAccessPoint")) { //DeviceWireless + Q_EMIT propertiesChanged(map); + } + } +} class QNetworkManagerInterfaceDeviceModemPrivate { @@ -607,7 +811,7 @@ public: }; QNetworkManagerInterfaceDeviceModem::QNetworkManagerInterfaceDeviceModem(const QString &ifaceDevicePath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { d = new QNetworkManagerInterfaceDeviceModemPrivate(); d->path = ifaceDevicePath; @@ -619,6 +823,25 @@ QNetworkManagerInterfaceDeviceModem::QNetworkManagerInterfaceDeviceModem(const Q d->valid = false; return; } + QDBusInterface deviceModemPropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus(),parent); + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM); + QDBusPendingReply propsReply + = deviceModemPropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); d->valid = true; } @@ -639,20 +862,7 @@ bool QNetworkManagerInterfaceDeviceModem::setConnections() if (!isValid() ) return false; - bool allOk = true; - - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - if (!QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_DEVICE_MODEM), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(slotDevicePropertiesChanged(QMap))) ) { - allOk = false; - } - return allOk; + return true; } QDBusInterface *QNetworkManagerInterfaceDeviceModem::connectionInterface() const @@ -660,14 +870,28 @@ QDBusInterface *QNetworkManagerInterfaceDeviceModem::connectionInterface() const return d->connectionInterface; } -quint32 QNetworkManagerInterfaceDeviceModem::modemCapabilities() const +QNetworkManagerInterfaceDeviceModem::ModemCapabilities QNetworkManagerInterfaceDeviceModem::modemCapabilities() const { - return d->connectionInterface->property("ModemCapabilities").toUInt(); + if (propertyMap.contains("ModemCapabilities")) + return static_cast(propertyMap.value("ModemCapabilities").toUInt()); + return QNetworkManagerInterfaceDeviceModem::None; } -quint32 QNetworkManagerInterfaceDeviceModem::currentCapabilities() const +QNetworkManagerInterfaceDeviceModem::ModemCapabilities QNetworkManagerInterfaceDeviceModem::currentCapabilities() const { - return d->connectionInterface->property("CurrentCapabilities").toUInt(); + if (propertyMap.contains("CurrentCapabilities")) + return static_cast(propertyMap.value("CurrentCapabilities").toUInt()); + return QNetworkManagerInterfaceDeviceModem::None; +} + +void QNetworkManagerInterfaceDeviceModem::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + } + Q_EMIT propertiesChanged(map); } class QNetworkManagerSettingsPrivate @@ -691,6 +915,14 @@ QNetworkManagerSettings::QNetworkManagerSettings(const QString &settingsService, d->valid = false; return; } + + QDBusPendingReply > nmReply + = d->connectionInterface->call(QLatin1String("ListConnections")); + + if (!nmReply.isError()) { + connectionsList = nmReply.value(); + } + d->valid = true; } @@ -722,10 +954,16 @@ bool QNetworkManagerSettings::setConnections() QList QNetworkManagerSettings::listConnections() { - QDBusReply > reply = d->connectionInterface->call(QLatin1String("ListConnections")); - return reply.value(); + if (connectionsList.isEmpty()) { + qWarning() << "Using blocking call!"; + QDBusReply > reply + = d->connectionInterface->call(QLatin1String("ListConnections")); + connectionsList = reply.value(); + } + return connectionsList; } + QString QNetworkManagerSettings::getConnectionByUuid(const QString &uuid) { QList argumentList; @@ -751,7 +989,7 @@ public: }; QNetworkManagerSettingsConnection::QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { qDBusRegisterMetaType(); d = new QNetworkManagerSettingsConnectionPrivate(); @@ -766,8 +1004,12 @@ QNetworkManagerSettingsConnection::QNetworkManagerSettingsConnection(const QStri return; } d->valid = true; - QDBusReply< QNmSettingsMap > rep = d->connectionInterface->call(QLatin1String("GetSettings")); - d->settingsMap = rep.value(); + + QDBusPendingReply nmReply + = d->connectionInterface->call(QLatin1String("GetSettings")); + if (!nmReply.isError()) { + d->settingsMap = nmReply.value(); + } } QNetworkManagerSettingsConnection::~QNetworkManagerSettingsConnection() @@ -783,7 +1025,7 @@ bool QNetworkManagerSettingsConnection::isValid() bool QNetworkManagerSettingsConnection::setConnections() { - if(!isValid() ) + if (!isValid()) return false; QDBusConnection dbusConnection = QDBusConnection::systemBus(); @@ -796,21 +1038,21 @@ bool QNetworkManagerSettingsConnection::setConnections() allOk = false; } - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForSettingsRemoved(QString)), - this,SIGNAL(removed(QString))); - if (!dbusConnection.connect(d->service, d->path, QLatin1String(NM_DBUS_IFACE_SETTINGS_CONNECTION), QLatin1String("Removed"), - nmDBusHelper, SIGNAL(slotSettingsRemoved()))) { + this, SIGNAL(slotSettingsRemoved()))) { allOk = false; } return allOk; } +void QNetworkManagerSettingsConnection::slotSettingsRemoved() +{ + Q_EMIT removed(d->path); +} + QDBusInterface *QNetworkManagerSettingsConnection::connectionInterface() const { return d->connectionInterface; @@ -818,8 +1060,11 @@ QDBusInterface *QNetworkManagerSettingsConnection::connectionInterface() const QNmSettingsMap QNetworkManagerSettingsConnection::getSettings() { - QDBusReply< QNmSettingsMap > rep = d->connectionInterface->call(QLatin1String("GetSettings")); - d->settingsMap = rep.value(); + if (d->settingsMap.isEmpty()) { + qWarning() << "Using blocking call!"; + QDBusReply reply = d->connectionInterface->call(QLatin1String("GetSettings")); + d->settingsMap = reply.value(); + } return d->settingsMap; } @@ -832,6 +1077,8 @@ NMDeviceType QNetworkManagerSettingsConnection::getType() return DEVICE_TYPE_ETHERNET; else if (devType == QLatin1String("802-11-wireless")) return DEVICE_TYPE_WIFI; + else if (devType == QLatin1String("gsm")) + return DEVICE_TYPE_MODEM; else return DEVICE_TYPE_UNKNOWN; } @@ -908,7 +1155,7 @@ public: }; QNetworkManagerConnectionActive::QNetworkManagerConnectionActive(const QString &activeConnectionObjectPath, QObject *parent) - : QObject(parent), nmDBusHelper(0) + : QObject(parent) { d = new QNetworkManagerConnectionActivePrivate(); d->path = activeConnectionObjectPath; @@ -920,6 +1167,29 @@ QNetworkManagerConnectionActive::QNetworkManagerConnectionActive(const QString & d->valid = false; return; } + QDBusInterface connectionActivePropertiesInterface(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String("org.freedesktop.DBus.Properties"), + QDBusConnection::systemBus()); + + + QList argumentList; + argumentList << QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION); + QDBusPendingReply propsReply + = connectionActivePropertiesInterface.callWithArgumentList(QDBus::Block,QLatin1String("GetAll"), + argumentList); + + if (!propsReply.isError()) { + propertyMap = propsReply.value(); + } else { + qWarning() << propsReply.error().message(); + } + + QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), + d->path, + QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION), + QLatin1String("PropertiesChanged"), + this,SLOT(propertiesSwap(QMap))); d->valid = true; } @@ -936,24 +1206,10 @@ bool QNetworkManagerConnectionActive::isValid() bool QNetworkManagerConnectionActive::setConnections() { - if(!isValid() ) + if (!isValid()) return false; - bool allOk = true; - delete nmDBusHelper; - nmDBusHelper = new QNmDBusHelper(this); - connect(nmDBusHelper, SIGNAL(pathForPropertiesChanged(QString,QMap)), - this,SIGNAL(propertiesChanged(QString,QMap))); - - if (!QDBusConnection::systemBus().connect(QLatin1String(NM_DBUS_SERVICE), - d->path, - QLatin1String(NM_DBUS_INTERFACE_ACTIVE_CONNECTION), - QLatin1String("PropertiesChanged"), - nmDBusHelper,SLOT(activeConnectionPropertiesChanged(QMap))) ) { - allOk = false; - } - - return allOk; + return true; } QDBusInterface *QNetworkManagerConnectionActive::connectionInterface() const @@ -963,30 +1219,67 @@ QDBusInterface *QNetworkManagerConnectionActive::connectionInterface() const QDBusObjectPath QNetworkManagerConnectionActive::connection() const { - QVariant prop = d->connectionInterface->property("Connection"); - return prop.value(); + if (propertyMap.contains("Connection")) + return propertyMap.value("Connection").value(); + return QDBusObjectPath(); } QDBusObjectPath QNetworkManagerConnectionActive::specificObject() const { - QVariant prop = d->connectionInterface->property("SpecificObject"); - return prop.value(); + if (propertyMap.contains("SpecificObject")) + return propertyMap.value("SpecificObject").value(); + return QDBusObjectPath(); } QList QNetworkManagerConnectionActive::devices() const { - QVariant prop = d->connectionInterface->property("Devices"); - return prop.value >(); + if (propertyMap.contains("Devices")) { + const QDBusArgument &dbusArgs = propertyMap.value("Devices").value(); + QDBusObjectPath path; + QList list; + + dbusArgs.beginArray(); + while (!dbusArgs.atEnd()) { + dbusArgs >> path; + list.append(path); + } + dbusArgs.endArray(); + + return list; + } + QList list; + list << QDBusObjectPath(); + return list; } quint32 QNetworkManagerConnectionActive::state() const { - return d->connectionInterface->property("State").toUInt(); + if (propertyMap.contains("State")) + return propertyMap.value("State").toUInt(); + return 0; } bool QNetworkManagerConnectionActive::defaultRoute() const { - return d->connectionInterface->property("Default").toBool(); + if (propertyMap.contains("Default")) + return propertyMap.value("Default").toBool(); + return false; +} + +void QNetworkManagerConnectionActive::propertiesSwap(QMap map) +{ + QMapIterator i(map); + while (i.hasNext()) { + i.next(); + propertyMap.insert(i.key(),i.value()); + if (i.key() == QStringLiteral("State")) { + quint32 state = i.value().toUInt(); + if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED + || state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { + Q_EMIT propertiesChanged(map); + } + } + } } class QNetworkManagerIp4ConfigPrivate diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 11ddaf7088..df4e5d49e1 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -56,7 +56,6 @@ #include #include #include -#include "qnmdbushelper.h" #ifndef QT_NO_DBUS @@ -89,7 +88,7 @@ typedef enum NM_ACTIVE_CONNECTION_STATE_UNKNOWN = 0, NM_ACTIVE_CONNECTION_STATE_ACTIVATING, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, - NM_ACTIVE_CONNECTION_STATE_DEACTIVATED + NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4 } NMActiveConnectionState; #define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" @@ -135,12 +134,23 @@ class QNetworkManagerInterface : public QObject Q_OBJECT public: + typedef enum + { + NM_STATE_UNKNOWN = 0, + NM_STATE_ASLEEP = 10, + NM_STATE_DISCONNECTED = 20, + NM_STATE_DISCONNECTING = 30, + NM_STATE_CONNECTING = 40, + NM_STATE_CONNECTED_LOCAL = 50, + NM_STATE_CONNECTED_SITE = 60, + NM_STATE_CONNECTED_GLOBAL = 70 + } NMState; QNetworkManagerInterface(QObject *parent = 0); ~QNetworkManagerInterface(); - QList getDevices() const; - void activateConnection(const QString &serviceName, QDBusObjectPath connection, QDBusObjectPath device, QDBusObjectPath specificObject); + QList getDevices(); + void activateConnection(QDBusObjectPath connection,QDBusObjectPath device, QDBusObjectPath specificObject); void deactivateConnection(QDBusObjectPath connectionPath) const; QDBusObjectPath path() const; @@ -149,21 +159,28 @@ public: bool wirelessEnabled() const; bool wirelessHardwareEnabled() const; QList activeConnections() const; - quint32 state(); + NMState state(); + QString version() const; bool setConnections(); bool isValid(); Q_SIGNALS: void deviceAdded(QDBusObjectPath); void deviceRemoved(QDBusObjectPath); - void propertiesChanged( const QString &, QMap); - void stateChanged(const QString&, quint32); + void propertiesChanged(QMap); + void stateChanged(quint32); void activationFinished(QDBusPendingCallWatcher*); + void propertiesReady(); + void devicesListReady(); private Q_SLOTS: + void propertiesSwap(QMap); + private: QNetworkManagerInterfacePrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; + QList devicesPathList; + }; class QNetworkManagerInterfaceAccessPointPrivate; @@ -228,11 +245,14 @@ public: Q_SIGNALS: void propertiesChanged(QMap ); - void propertiesChanged( const QString &, QMap); + void propertiesReady(); + +private Q_SLOTS: + void propertiesSwap(QMap); + private: QNetworkManagerInterfaceAccessPointPrivate *d; - QNmDBusHelper *nmDBusHelper; - + QVariantMap propertyMap; }; class QNetworkManagerInterfaceDevicePrivate; @@ -258,11 +278,14 @@ public: Q_SIGNALS: void stateChanged(const QString &, quint32); - void propertiesChanged(const QString &, QMap); + void propertiesChanged(QMap); void connectionsChanged(QStringList); + void propertiesReady(); +private Q_SLOTS: + void propertiesSwap(QMap); private: QNetworkManagerInterfaceDevicePrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; }; class QNetworkManagerInterfaceDeviceWiredPrivate; @@ -284,10 +307,15 @@ public: bool isValid(); Q_SIGNALS: - void propertiesChanged( const QString &, QMap); + void propertiesChanged(QMap); + void propertiesReady(); + +private Q_SLOTS: + void propertiesSwap(QMap); + private: QNetworkManagerInterfaceDeviceWiredPrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; }; class QNetworkManagerInterfaceDeviceWirelessPrivate; @@ -325,15 +353,24 @@ public: void requestScan(); Q_SIGNALS: - void propertiesChanged( const QString &, QMap); + void propertiesChanged(QMap); void accessPointAdded(const QString &); void accessPointRemoved(const QString &); void scanDone(); + void propertiesReady(); + void accessPointsReady(); + private Q_SLOTS: void scanIsDone(); + void propertiesSwap(QMap); + + void slotAccessPointAdded(QDBusObjectPath); + void slotAccessPointRemoved(QDBusObjectPath); + private: QNetworkManagerInterfaceDeviceWirelessPrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; + QList accessPointsList; }; class QNetworkManagerInterfaceDeviceModemPrivate; @@ -350,6 +387,7 @@ public: Gsm_Umts = 0x4, Lte = 0x08 }; + Q_DECLARE_FLAGS(ModemCapabilities, ModemCapability) explicit QNetworkManagerInterfaceDeviceModem(const QString &ifaceDevicePath, QObject *parent = 0); @@ -361,16 +399,22 @@ public: bool setConnections(); bool isValid(); - quint32 modemCapabilities() const; - quint32 currentCapabilities() const; + ModemCapabilities modemCapabilities() const; + ModemCapabilities currentCapabilities() const; Q_SIGNALS: - void propertiesChanged( const QString &, QMap); + void propertiesChanged(QMap); + void propertiesReady(); + +private Q_SLOTS: + void propertiesSwap(QMap); + private: QNetworkManagerInterfaceDeviceModemPrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QNetworkManagerInterfaceDeviceModem::ModemCapabilities) class QNetworkManagerSettingsPrivate; class QNetworkManagerSettings : public QObject @@ -390,8 +434,10 @@ public: Q_SIGNALS: void newConnection(QDBusObjectPath); + void connectionsListReady(); private: QNetworkManagerSettingsPrivate *d; + QList connectionsList; }; class QNetworkManagerSettingsConnectionPrivate; @@ -418,12 +464,14 @@ public: bool isValid(); Q_SIGNALS: - void updated(); void removed(const QString &path); + void settingsReady(); + +private Q_SLOTS: + void slotSettingsRemoved(); private: - QNmDBusHelper *nmDBusHelper; QNetworkManagerSettingsConnectionPrivate *d; }; @@ -444,7 +492,6 @@ public: ~ QNetworkManagerConnectionActive(); QDBusInterface *connectionInterface() const; - QString serviceName() const; QDBusObjectPath connection() const; QDBusObjectPath specificObject() const; QList devices() const; @@ -455,11 +502,15 @@ public: Q_SIGNALS: - void propertiesChanged(QList); - void propertiesChanged( const QString &, QMap); + void propertiesChanged(QMap); + void propertiesReady(); + +private Q_SLOTS: + void propertiesSwap(QMap); + private: QNetworkManagerConnectionActivePrivate *d; - QNmDBusHelper *nmDBusHelper; + QVariantMap propertyMap; }; class QNetworkManagerIp4ConfigPrivate; diff --git a/src/plugins/bearer/networkmanager/qnmdbushelper.cpp b/src/plugins/bearer/networkmanager/qnmdbushelper.cpp deleted file mode 100644 index 0decfd78b9..0000000000 --- a/src/plugins/bearer/networkmanager/qnmdbushelper.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// this class is for helping qdbus get stuff - -#include "qnmdbushelper.h" - -#include "qnetworkmanagerservice.h" - -#include -#include -#include -#include - -#include - -#ifndef QT_NO_DBUS - -QT_BEGIN_NAMESPACE - -QNmDBusHelper::QNmDBusHelper(QObject * parent) - : QObject(parent) -{ -} - -QNmDBusHelper::~QNmDBusHelper() -{ -} - -void QNmDBusHelper::deviceStateChanged(quint32 state) - { - QDBusMessage msg = this->message(); - if (state == NM_DEVICE_STATE_ACTIVATED - || state == NM_DEVICE_STATE_DISCONNECTED - || state == NM_DEVICE_STATE_UNAVAILABLE - || state == NM_DEVICE_STATE_FAILED) { - emit pathForStateChanged(msg.path(), state); - } - } - -void QNmDBusHelper::slotAccessPointAdded(QDBusObjectPath path) -{ - if (path.path().length() > 2) - emit pathForAccessPointAdded(path.path()); -} - -void QNmDBusHelper::slotAccessPointRemoved(QDBusObjectPath path) -{ - if (path.path().length() > 2) - emit pathForAccessPointRemoved(path.path()); -} - -void QNmDBusHelper::slotPropertiesChanged(QMap map) -{ - QDBusMessage msg = this->message(); - QMapIterator i(map); - while (i.hasNext()) { - i.next(); - if (i.key() == QStringLiteral("State")) { - quint32 state = i.value().toUInt(); - if (state == NM_DEVICE_STATE_ACTIVATED - || state == NM_DEVICE_STATE_DISCONNECTED - || state == NM_DEVICE_STATE_UNAVAILABLE - || state == NM_DEVICE_STATE_FAILED) { - emit pathForPropertiesChanged(msg.path(), map); - } - } else if (i.key() == QStringLiteral("ActiveAccessPoint")) { - emit pathForPropertiesChanged(msg.path(), map); - } else if (i.key() == QStringLiteral("ActiveConnections")) { - emit pathForPropertiesChanged(msg.path(), map); - } else if (i.key() == QStringLiteral("AvailableConnections")) { - const QDBusArgument &dbusArgs = i.value().value(); - QDBusObjectPath path; - QStringList paths; - dbusArgs.beginArray(); - while (!dbusArgs.atEnd()) { - dbusArgs >> path; - paths << path.path(); - } - dbusArgs.endArray(); - emit pathForConnectionsChanged(paths); - } - } -} - -void QNmDBusHelper::slotSettingsRemoved() -{ - QDBusMessage msg = this->message(); - emit pathForSettingsRemoved(msg.path()); -} - -void QNmDBusHelper::activeConnectionPropertiesChanged(QMap map) -{ - QDBusMessage msg = this->message(); - QMapIterator i(map); - while (i.hasNext()) { - i.next(); - if (i.key() == QStringLiteral("State")) { - quint32 state = i.value().toUInt(); - if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED - || state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { - emit pathForPropertiesChanged(msg.path(), map); - } - } - } -} - -QT_END_NAMESPACE - -#endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnmdbushelper.h b/src/plugins/bearer/networkmanager/qnmdbushelper.h deleted file mode 100644 index e224af87f1..0000000000 --- a/src/plugins/bearer/networkmanager/qnmdbushelper.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QNMDBUSHELPERPRIVATE_H -#define QNMDBUSHELPERPRIVATE_H - -#include -#include -#include - -#ifndef QT_NO_DBUS - -QT_BEGIN_NAMESPACE - -class QNmDBusHelper: public QObject, protected QDBusContext - { - Q_OBJECT - public: - QNmDBusHelper(QObject *parent = 0); - ~QNmDBusHelper(); - - public slots: - void deviceStateChanged(quint32); - void slotAccessPointAdded(QDBusObjectPath); - void slotAccessPointRemoved(QDBusObjectPath); - void slotPropertiesChanged(QMap); - void slotSettingsRemoved(); - void activeConnectionPropertiesChanged(QMap); - -Q_SIGNALS: - void pathForStateChanged(const QString &, quint32); - void pathForAccessPointAdded(const QString &); - void pathForAccessPointRemoved(const QString &); - void pathForPropertiesChanged(const QString &, QMap); - void pathForSettingsRemoved(const QString &); - void pathForConnectionsChanged(const QStringList &pathsList); -}; - -QT_END_NAMESPACE - -#endif // QT_NO_DBUS - -#endif// QNMDBUSHELPERPRIVATE_H From 0b54de41bc6beeddc0453a3f31527eaaf53ffee5 Mon Sep 17 00:00:00 2001 From: Axel Rasmussen Date: Sun, 2 Nov 2014 15:02:07 -0700 Subject: [PATCH 168/323] moc: use Q_NULLPTR instead of 0 in generated code. This commit changes several instances where moc was generating code that used 0 as a null pointer constant. The Q_NULLPTR define is the more idiomatic way to do this, and additionally this silences warnings generated by e.g. GCC's -Wzero-as-null-pointer-constant. [ChangeLog][Tools][moc] Fixed "zero as null pointer constant" warnings in moc's generated code. Change-Id: Ibe382b7bdbdddaf20cb4bdfd075fcdd1f363f9d3 Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart --- src/tools/moc/generator.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index dd032e46f6..6c5e772e8c 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -493,7 +493,7 @@ void Generator::generateCode() for (int i = 0; i < extraList.count(); ++i) { fprintf(out, " &%s::staticMetaObject,\n", extraList.at(i).constData()); } - fprintf(out, " 0\n};\n\n"); + fprintf(out, " Q_NULLPTR\n};\n\n"); } // @@ -505,24 +505,24 @@ void Generator::generateCode() fprintf(out, "const QMetaObject %s::staticMetaObject = {\n", cdef->qualified.constData()); if (isQObject) - fprintf(out, " { 0, "); + fprintf(out, " { Q_NULLPTR, "); else if (cdef->superclassList.size()) fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData()); else - fprintf(out, " { 0, "); + fprintf(out, " { Q_NULLPTR, "); fprintf(out, "qt_meta_stringdata_%s.data,\n" " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); if (cdef->hasQObject && !isQt) fprintf(out, " qt_static_metacall, "); else - fprintf(out, " 0, "); + fprintf(out, " Q_NULLPTR, "); if (extraList.isEmpty()) - fprintf(out, "0, "); + fprintf(out, "Q_NULLPTR, "); else fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData()); - fprintf(out, "0}\n};\n\n"); + fprintf(out, "Q_NULLPTR}\n};\n\n"); if(isQt) return; @@ -537,7 +537,7 @@ void Generator::generateCode() // Generate smart cast function // fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData()); - fprintf(out, " if (!_clname) return 0;\n"); + fprintf(out, " if (!_clname) return Q_NULLPTR;\n"); fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata))\n" " return static_cast(const_cast< %s*>(this));\n", qualifiedClassNameIdentifier.constData(), cdef->classname.constData()); @@ -562,7 +562,7 @@ void Generator::generateCode() QByteArray superClass = purestSuperClass; fprintf(out, " return %s::qt_metacast(_clname);\n", superClass.constData()); } else { - fprintf(out, " return 0;\n"); + fprintf(out, " return Q_NULLPTR;\n"); } fprintf(out, "}\n"); @@ -1416,7 +1416,7 @@ void Generator::generateSignal(FunctionDef *def,int index) fprintf(out, "QPrivateSignal"); fprintf(out, ")%s\n{\n" - " QMetaObject::activate(%s, &staticMetaObject, %d, 0);\n" + " QMetaObject::activate(%s, &staticMetaObject, %d, Q_NULLPTR);\n" "}\n", constQualifier, thisPtr.constData(), index); return; } @@ -1446,7 +1446,7 @@ void Generator::generateSignal(FunctionDef *def,int index) fprintf(out, " void *_a[] = { "); if (def->normalizedType == "void") { - fprintf(out, "0"); + fprintf(out, "Q_NULLPTR"); } else { if (def->returnTypeIsVolatile) fprintf(out, "const_cast(reinterpret_cast(&_t0))"); From 3c0ea78283b6c231854192e4e8519e02d70887d8 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 5 Nov 2014 12:56:26 +0400 Subject: [PATCH 169/323] Do not pass a null pointer to unlink() Found by clang static analyzer. Change-Id: I8f15ae1a8e6afb91eafa6cee1d1b21e3539af6c1 Reviewed-by: Friedemann Kleint Reviewed-by: Andy Shaw --- src/plugins/printsupport/cups/qppdprintdevice.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp index 7a6acf8b78..d20fbb558b 100644 --- a/src/plugins/printsupport/cups/qppdprintdevice.cpp +++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp @@ -470,9 +470,10 @@ void QPpdPrintDevice::loadPrinter() m_cupsDest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, m_cupsName, m_cupsInstance); if (m_cupsDest) { const char *ppdFile = cupsGetPPD(m_cupsName); - if (ppdFile) + if (ppdFile) { m_ppd = ppdOpenFile(ppdFile); - unlink(ppdFile); + unlink(ppdFile); + } if (m_ppd) { ppdMarkDefaults(m_ppd); } else { From df106921b2f3d24dca5639104f0b5074044aef2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Wed, 5 Nov 2014 20:42:07 +0100 Subject: [PATCH 170/323] Android: Fix for build issue on x86 In the toolchain for x86 the va_list type is defined as char *, which in itself isn't strange, but it was somewhat unexpected as it differs from the arm toolchains. Either way we should not make assumption about the va_list type as there is no guarantee it won't cause conflicts when overloading. This fix simply renames the private overloads. Change-Id: I7808619d0fa3ca63b75796308cfdff6aa41a7fd0 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/corelib/kernel/qjni.cpp | 248 ++++++++++++++++++------------------ src/corelib/kernel/qjni_p.h | 46 ++++--- 2 files changed, 150 insertions(+), 144 deletions(-) diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp index 452e3464d6..b179323fdc 100644 --- a/src/corelib/kernel/qjni.cpp +++ b/src/corelib/kernel/qjni.cpp @@ -311,7 +311,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, ... } } -QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, va_list args) +QJNIObjectPrivate::QJNIObjectPrivate(const char *className, const char *sig, const QVaListPrivate &args) : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; @@ -369,7 +369,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, ...) } } -QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, va_list args) +QJNIObjectPrivate::QJNIObjectPrivate(jclass clazz, const char *sig, const QVaListPrivate &args) : d(new QJNIObjectData()) { QJNIEnvironmentPrivate env; @@ -402,7 +402,7 @@ QJNIObjectPrivate::QJNIObjectPrivate(jobject obj) } template <> -void QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +void QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jmethodID id = getCachedMethodID(env, d->m_jclass, methodName, sig); @@ -416,12 +416,12 @@ void QJNIObjectPrivate::callMethod(const char *methodName, const char *sig { va_list args; va_start(args, sig); - callMethod(methodName, sig, args); + callMethodV(methodName, sig, args); va_end(args); } template <> -jboolean QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jboolean QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jboolean res = 0; @@ -437,13 +437,13 @@ jboolean QJNIObjectPrivate::callMethod(const char *methodName, const c { va_list args; va_start(args, sig); - jboolean res = callMethod(methodName, sig, args); + jboolean res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jbyte QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jbyte QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jbyte res = 0; @@ -459,13 +459,13 @@ jbyte QJNIObjectPrivate::callMethod(const char *methodName, const char *s { va_list args; va_start(args, sig); - jbyte res = callMethod(methodName, sig, args); + jbyte res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jchar QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jchar QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jchar res = 0; @@ -481,13 +481,13 @@ jchar QJNIObjectPrivate::callMethod(const char *methodName, const char *s { va_list args; va_start(args, sig); - jchar res = callMethod(methodName, sig, args); + jchar res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jshort QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jshort QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jshort res = 0; @@ -503,13 +503,13 @@ jshort QJNIObjectPrivate::callMethod(const char *methodName, const char { va_list args; va_start(args, sig); - jshort res = callMethod(methodName, sig, args); + jshort res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jint QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jint QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jint res = 0; @@ -525,13 +525,13 @@ jint QJNIObjectPrivate::callMethod(const char *methodName, const char *sig { va_list args; va_start(args, sig); - jint res = callMethod(methodName, sig, args); + jint res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jlong QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jlong QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jlong res = 0; @@ -547,13 +547,13 @@ jlong QJNIObjectPrivate::callMethod(const char *methodName, const char *s { va_list args; va_start(args, sig); - jlong res = callMethod(methodName, sig, args); + jlong res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jfloat QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jfloat QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jfloat res = 0.f; @@ -569,13 +569,13 @@ jfloat QJNIObjectPrivate::callMethod(const char *methodName, const char { va_list args; va_start(args, sig); - jfloat res = callMethod(methodName, sig, args); + jfloat res = callMethodV(methodName, sig, args); va_end(args); return res; } template <> -jdouble QJNIObjectPrivate::callMethod(const char *methodName, const char *sig, va_list args) const +jdouble QJNIObjectPrivate::callMethodV(const char *methodName, const char *sig, va_list args) const { QJNIEnvironmentPrivate env; jdouble res = 0.; @@ -591,7 +591,7 @@ jdouble QJNIObjectPrivate::callMethod(const char *methodName, const cha { va_list args; va_start(args, sig); - jdouble res = callMethod(methodName, sig, args); + jdouble res = callMethodV(methodName, sig, args); va_end(args); return res; } @@ -651,10 +651,10 @@ jdouble QJNIObjectPrivate::callMethod(const char *methodName) const } template <> -void QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +void QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jclass clazz = loadClass(className, env); @@ -674,15 +674,15 @@ void QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - callStaticMethod(className, methodName, sig, args); + callStaticMethodV(className, methodName, sig, args); va_end(args); } template <> -void QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +void QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jmethodID id = getCachedMethodID(env, clazz, methodName, sig, true); @@ -699,15 +699,15 @@ void QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - callStaticMethod(clazz, methodName, sig, args); + callStaticMethodV(clazz, methodName, sig, args); va_end(args); } template <> -jboolean QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jboolean QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jboolean res = 0; @@ -730,16 +730,16 @@ jboolean QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jboolean res = callStaticMethod(className, methodName, sig, args); + jboolean res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jboolean QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jboolean QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jboolean res = 0; @@ -759,16 +759,16 @@ jboolean QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jboolean res = callStaticMethod(clazz, methodName, sig, args); + jboolean res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jbyte QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jbyte QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jbyte res = 0; @@ -791,16 +791,16 @@ jbyte QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jbyte res = callStaticMethod(className, methodName, sig, args); + jbyte res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jbyte QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jbyte QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jbyte res = 0; @@ -820,16 +820,16 @@ jbyte QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jbyte res = callStaticMethod(clazz, methodName, sig, args); + jbyte res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jchar QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jchar QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jchar res = 0; @@ -852,16 +852,16 @@ jchar QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jchar res = callStaticMethod(className, methodName, sig, args); + jchar res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jchar QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jchar QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jchar res = 0; @@ -881,16 +881,16 @@ jchar QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jchar res = callStaticMethod(clazz, methodName, sig, args); + jchar res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jshort QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jshort QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jshort res = 0; @@ -913,16 +913,16 @@ jshort QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jshort res = callStaticMethod(className, methodName, sig, args); + jshort res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jshort QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jshort QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jshort res = 0; @@ -942,16 +942,16 @@ jshort QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jshort res = callStaticMethod(clazz, methodName, sig, args); + jshort res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jint QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jint QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jint res = 0; @@ -974,16 +974,16 @@ jint QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jint res = callStaticMethod(className, methodName, sig, args); + jint res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jint QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jint QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jint res = 0; @@ -1003,16 +1003,16 @@ jint QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jint res = callStaticMethod(clazz, methodName, sig, args); + jint res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jlong QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jlong QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jlong res = 0; @@ -1035,16 +1035,16 @@ jlong QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jlong res = callStaticMethod(className, methodName, sig, args); + jlong res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jlong QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jlong QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jlong res = 0; @@ -1064,16 +1064,16 @@ jlong QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jlong res = callStaticMethod(clazz, methodName, sig, args); + jlong res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jfloat QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jfloat QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jfloat res = 0.f; @@ -1096,16 +1096,16 @@ jfloat QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jfloat res = callStaticMethod(className, methodName, sig, args); + jfloat res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jfloat QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jfloat QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jfloat res = 0.f; @@ -1125,16 +1125,16 @@ jfloat QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jfloat res = callStaticMethod(clazz, methodName, sig, args); + jfloat res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } template <> -jdouble QJNIObjectPrivate::callStaticMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +jdouble QJNIObjectPrivate::callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jdouble res = 0.; @@ -1157,16 +1157,16 @@ jdouble QJNIObjectPrivate::callStaticMethod(const char *className, { va_list args; va_start(args, sig); - jdouble res = callStaticMethod(className, methodName, sig, args); + jdouble res = callStaticMethodV(className, methodName, sig, args); va_end(args); return res; } template <> -jdouble QJNIObjectPrivate::callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +jdouble QJNIObjectPrivate::callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jdouble res = 0.; @@ -1186,7 +1186,7 @@ jdouble QJNIObjectPrivate::callStaticMethod(jclass clazz, { va_list args; va_start(args, sig); - jdouble res = callStaticMethod(clazz, methodName, sig, args); + jdouble res = callStaticMethodV(clazz, methodName, sig, args); va_end(args); return res; } @@ -1299,9 +1299,9 @@ jdouble QJNIObjectPrivate::callStaticMethod(jclass clazz, const char *m return callStaticMethod(clazz, methodName, "()D"); } -QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName, - const char *sig, - va_list args) const +QJNIObjectPrivate QJNIObjectPrivate::callObjectMethodV(const char *methodName, + const char *sig, + va_list args) const { QJNIEnvironmentPrivate env; jobject res = 0; @@ -1323,7 +1323,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char *methodName, { va_list args; va_start(args, sig); - QJNIObjectPrivate res = callObjectMethod(methodName, sig, args); + QJNIObjectPrivate res = callObjectMethodV(methodName, sig, args); va_end(args); return res; } @@ -1376,10 +1376,10 @@ QJNIObjectPrivate QJNIObjectPrivate::callObjectMethod(const char * return callObjectMethod(methodName, "()[D"); } -QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(const char *className, - const char *methodName, - const char *sig, - va_list args) +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jobject res = 0; @@ -1405,15 +1405,15 @@ QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(const char *classNam { va_list args; va_start(args, sig); - QJNIObjectPrivate res = callStaticObjectMethod(className, methodName, sig, args); + QJNIObjectPrivate res = callStaticObjectMethodV(className, methodName, sig, args); va_end(args); return res; } -QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(jclass clazz, - const char *methodName, - const char *sig, - va_list args) +QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args) { QJNIEnvironmentPrivate env; jobject res = 0; @@ -1436,7 +1436,7 @@ QJNIObjectPrivate QJNIObjectPrivate::callStaticObjectMethod(jclass clazz, { va_list args; va_start(args, sig); - QJNIObjectPrivate res = callStaticObjectMethod(clazz, methodName, sig, args); + QJNIObjectPrivate res = callStaticObjectMethodV(clazz, methodName, sig, args); va_end(args); return res; } diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h index 19f2cf7601..5f573624c6 100644 --- a/src/corelib/kernel/qjni_p.h +++ b/src/corelib/kernel/qjni_p.h @@ -186,31 +186,37 @@ public: private: friend class QAndroidJniObject; - QJNIObjectPrivate(const char *className, const char *sig, va_list args); - QJNIObjectPrivate(jclass clazz, const char *sig, va_list args); + struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; }; + + QJNIObjectPrivate(const char *className, const char *sig, const QVaListPrivate &args); + QJNIObjectPrivate(jclass clazz, const char *sig, const QVaListPrivate &args); template - T callMethod(const char *methodName, - const char *sig, - va_list args) const; - QJNIObjectPrivate callObjectMethod(const char *methodName, - const char *sig, - va_list args) const; + T callMethodV(const char *methodName, + const char *sig, + va_list args) const; + QJNIObjectPrivate callObjectMethodV(const char *methodName, + const char *sig, + va_list args) const; template - static T callStaticMethod(const char *className, - const char *methodName, - const char *sig, va_list args); + static T callStaticMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args); template - static T callStaticMethod(jclass clazz, - const char *methodName, - const char *sig, va_list args); - static QJNIObjectPrivate callStaticObjectMethod(const char *className, - const char *methodName, - const char *sig, va_list args); + static T callStaticMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args); + static QJNIObjectPrivate callStaticObjectMethodV(const char *className, + const char *methodName, + const char *sig, + va_list args); - static QJNIObjectPrivate callStaticObjectMethod(jclass clazz, - const char *methodName, - const char *sig, va_list args); + static QJNIObjectPrivate callStaticObjectMethodV(jclass clazz, + const char *methodName, + const char *sig, + va_list args); bool isSameObject(jobject obj) const; bool isSameObject(const QJNIObjectPrivate &other) const; From 9c8943a862a5762eef0ae98f2b6b14e5c449105c Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 24 Oct 2014 12:07:32 +0200 Subject: [PATCH 171/323] Doc: updated documentation QString::toDouble Task-number: QTBUG-35543 Change-Id: I60d5cc253e6d6a24e9b031758e16a547a9a07443 Reviewed-by: Martin Smith --- src/corelib/tools/qstring.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 48f251e3f4..543c75668f 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6339,8 +6339,7 @@ ushort QString::toUShort(bool *ok, int base) const \snippet qstring/main.cpp 66 - Various string formats for floating point numbers can be converted - to double values: + \warning The QString content may only contain valid numerical characters which includes the plus/minus sign, the characters g and e used in scientific notation, and the decimal point. Including the unit or additional characters leads to a conversion error. \snippet qstring/main.cpp 67 @@ -6349,7 +6348,7 @@ ushort QString::toUShort(bool *ok, int base) const \snippet qstring/main.cpp 68 - For historic reasons, this function does not handle + For historical reasons, this function does not handle thousands group separators. If you need to convert such numbers, use QLocale::toDouble(). From 30d9498329489020f1720841ac960e06e2e7c5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 27 Oct 2014 16:11:58 +0100 Subject: [PATCH 172/323] iOS: Detect when inputMethodAccepted() is out of sync with focus object The GraphicsView stack still seems to have issues emitting focusObject change signals when the focus object changes inside the item hierarchy. To be on the safe side we use our own view of whether or not IM is enabled, and try to detect and warn if we find a case where the two are out of sync. Change-Id: I9fde896ea14ea5b65784723110887e06453edbd4 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosinputcontext.h | 1 + src/plugins/platforms/ios/qiosinputcontext.mm | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 5791367d84..f07408db81 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -82,6 +82,7 @@ public: void commit(); const ImeState &imeState() { return m_imeState; }; + bool inputMethodAccepted() const; bool isReloadingInputViewsFromUpdate() const { return m_isReloadingInputViewsFromUpdate; } diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index c038628fd9..25d9f6c421 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -486,6 +486,26 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) } } +bool QIOSInputContext::inputMethodAccepted() const +{ + // The IM enablement state is based on the last call to update() + bool lastKnownImEnablementState = m_imeState.currentState.value(Qt::ImEnabled).toBool(); + +#if !defined(QT_NO_DEBUG) + // QPlatformInputContext keeps a cached value of the current IM enablement state that is + // updated by QGuiApplication when the current focus object changes, or by QInputMethod's + // update() function. If the focus object changes, but the change is not propagated as + // a signal to QGuiApplication due to bugs in the widget/graphicsview/qml stack, we'll + // end up with a stale value for QPlatformInputContext::inputMethodAccepted(). To be on + // the safe side we always use our own cached value to decide if IM is enabled, and try + // to detect the case where the two values are out of sync. + if (lastKnownImEnablementState != QPlatformInputContext::inputMethodAccepted()) + qWarning("QPlatformInputContext::inputMethodAccepted() does not match actual focus object IM enablement!"); +#endif + + return lastKnownImEnablementState; +} + /*! Called by the input item to reset the input method state. */ From 79f832594dc103ef4a663153f8b9a88691e46233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= Date: Wed, 8 Oct 2014 15:11:31 +0300 Subject: [PATCH 173/323] eglfs: obey QT_NO_REGULAREXPRESSION define Not all platforms do have QRegularExpression as it is based on pcre. Change-Id: I6b8e701ff7cf30e776ee34e5dc836cd24c9543b5 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/qeglfshooks_stub.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp index b6b1be9244..26d77a2abb 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp @@ -63,11 +63,13 @@ QByteArray QEglFSHooks::fbDeviceName() const int QEglFSHooks::framebufferIndex() const { int fbIndex = 0; +#ifndef QT_NO_REGULAREXPRESSION QRegularExpression fbIndexRx(QLatin1String("fb(\\d+)")); QRegularExpressionMatch match = fbIndexRx.match(fbDeviceName()); if (match.hasMatch()) fbIndex = match.captured(1).toInt(); +#endif return fbIndex; } From c493546a0a1bbf1455f67092364bdba18e43ba01 Mon Sep 17 00:00:00 2001 From: Eike Hein Date: Mon, 13 Oct 2014 21:33:57 +0200 Subject: [PATCH 174/323] Merge TextFormat attributes for identical ranges in QInputMethodEvents IBus can hand us multiple attributes for different formatting properties of the same text range for events. The IBus input method plugin used to convert these straight into multiple QInputMethodEvent::Attributes, each with their own QTextCharFormat instance. According to the QInputMethodEvent documentation, behavior with multiple TextFormat attributes for the same text range is undefined. In at least one known user, KDE's Kate text editor, it causes invisible text for pre-edit text events as the QTextCharFormats are applied in turn with partially default-constructed foreground/background brushes: https://bugs.kde.org/show_bug.cgi?id=339467 This patch makes an effort to merge formatting information for identical text ranges into a single QTextCharFomat, while otherwise preserving existing behavior (attribute order is unchanged and attributes deseria- lized from D-Bus as having invalid QTextFormats remain untouched). No attempt is made to cope with overlapping text ranges. Segmenting into smaller ranges and merging for the overlaps would be conceivable, but until a case of an input method creating events with overlapping ranges is known seems not worth the effort. It's worth noting that the IBus input method plugin for Qt 4 also attempts to merge formatting information into a single QTextCharFormat, but with a distinct implementation from this one. Change-Id: Ie3dc38b353724ffb7b5f2d7f316393027373baf2 Task-number: 41640 Reviewed-by: Simon Hausmann --- .../platforminputcontexts/ibus/qibustypes.cpp | 28 ++++++++++++++++--- .../platforminputcontexts/ibus/qibustypes.h | 3 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp index 9bc53ed5c0..ec8c746b2d 100644 --- a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp @@ -32,7 +32,6 @@ ****************************************************************************/ #include "qibustypes.h" -#include #include #include @@ -134,7 +133,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusAttribute &a return argument; } -QTextFormat QIBusAttribute::format() const +QTextCharFormat QIBusAttribute::format() const { QTextCharFormat fmt; switch (type) { @@ -225,11 +224,32 @@ const QDBusArgument &operator>>(const QDBusArgument &arg, QIBusAttributeList &at QList QIBusAttributeList::imAttributes() const { - QList imAttrs; + QHash, QTextCharFormat> rangeAttrs; + + // Merge text fomats for identical ranges into a single QTextFormat. for (int i = 0; i < attributes.size(); ++i) { const QIBusAttribute &attr = attributes.at(i); - imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, attr.start, attr.end - attr.start, attr.format()); + const QTextCharFormat &format = attr.format(); + + if (format.isValid()) { + const QPair range(attr.start, attr.end); + rangeAttrs[range].merge(format); + } } + + // Assemble list in original attribute order. + QList imAttrs; + + for (int i = 0; i < attributes.size(); ++i) { + const QIBusAttribute &attr = attributes.at(i); + const QTextFormat &format = attr.format(); + + imAttrs += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + attr.start, + attr.end - attr.start, + format.isValid() ? rangeAttrs[QPair(attr.start, attr.end)] : format); + } + return imAttrs; } diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.h b/src/plugins/platforminputcontexts/ibus/qibustypes.h index 2ec3b019ff..96791b17a1 100644 --- a/src/plugins/platforminputcontexts/ibus/qibustypes.h +++ b/src/plugins/platforminputcontexts/ibus/qibustypes.h @@ -36,6 +36,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ public: QIBusAttribute(); ~QIBusAttribute(); - QTextFormat format() const; + QTextCharFormat format() const; Type type; quint32 value; From 13401116cce64bc7f2cf80b07ce34a4ad3abe829 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 6 Sep 2014 13:07:37 +0300 Subject: [PATCH 175/323] Remove incorrect read from QSslSocket::readData() QIODevice makes readData() call only when its read buffer is empty. Also data argument points to the user or reserved read buffer area. So, no need in data transfer from read buffer at this point at all. Task-number: QTBUG-41797 Change-Id: Ieb4afdf7eec37fdf288073e4a060e64424f22b9c Reviewed-by: Thiago Macieira (cherry picked from commit 1853579dad1bbb44599314213a1d8a203ecae1c9) Reviewed-by: Alex Trotsenko Reviewed-by: Oswald Buddenhagen --- src/network/ssl/qsslsocket.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 27b085ddbd..8887f478dd 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -1908,18 +1908,14 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen) if (d->mode == UnencryptedMode && !d->autoStartHandshake) { readBytes = d->plainSocket->read(data, maxlen); - } else { - int bytesToRead = qMin(maxlen, d->buffer.size()); - readBytes = d->buffer.read(data, bytesToRead); - } - #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::readData(" << (void *)data << ',' << maxlen << ") ==" << readBytes; + qDebug() << "QSslSocket::readData(" << (void *)data << ',' << maxlen << ") ==" + << readBytes; #endif - - // possibly trigger another transmit() to decrypt more data from the socket - if (d->buffer.isEmpty() && d->plainSocket->bytesAvailable()) { - QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection); + } else { + // possibly trigger another transmit() to decrypt more data from the socket + if (d->plainSocket->bytesAvailable()) + QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection); } return readBytes; From 999fa634829bf90e939f2fc14678a842eb49c75e Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Tue, 4 Nov 2014 17:59:24 +1000 Subject: [PATCH 176/323] Support dual sim in QtBearer's networkmanager backend Task-number: QTBUG-42368 Change-Id: I306733b5de7871fdeaa0accb512a3610753c84a5 Reviewed-by: Alex Blasche --- .../linux_common/qofonoservice_linux.cpp | 9 +- .../linux_common/qofonoservice_linux_p.h | 1 + .../networkmanager/qnetworkmanagerengine.cpp | 88 ++++++++++--------- .../networkmanager/qnetworkmanagerengine.h | 6 +- 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp index e994ebf2ce..b2e2131a92 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp +++ b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp @@ -112,7 +112,8 @@ QString QOfonoManagerInterface::currentModem() QStringList modems = getModems(); foreach (const QString &modem, modems) { QOfonoModemInterface device(modem); - if (device.isPowered() && device.isOnline()) + if (device.isPowered() && device.isOnline() + && device.interfaces().contains(QStringLiteral("org.ofono.NetworkRegistration"))) return modem; } return QString(); @@ -169,6 +170,12 @@ bool QOfonoModemInterface::isOnline() return qdbus_cast(var); } +QStringList QOfonoModemInterface::interfaces() +{ + const QVariant var = getProperty(QStringLiteral("Interfaces")); + return var.toStringList(); +} + QVariantMap QOfonoModemInterface::getProperties() { if (propertiesMap.isEmpty()) { diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h index 2b3d43deb5..0ed00d94ff 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h +++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h @@ -115,6 +115,7 @@ public: bool isPowered(); bool isOnline(); + QStringList interfaces(); private: QVariantMap getProperties(); QVariantMap propertiesMap; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index f07d7b242b..9adadb8f4f 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -58,9 +58,7 @@ QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) : QBearerEngineImpl(parent), managerInterface(new QNetworkManagerInterface(this)), systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE, this)), - ofonoManager(new QOfonoManagerInterface(this)), - ofonoNetwork(0), - ofonoContextManager(0) + ofonoManager(new QOfonoManagerInterface(this)) { if (!managerInterface->isValid()) @@ -97,16 +95,22 @@ QNetworkManagerEngine::~QNetworkManagerEngine() interfaceDevices.clear(); connectionInterfaces.clear(); + + qDeleteAll(ofonoContextManagers); + ofonoContextManagers.clear(); } void QNetworkManagerEngine::initialize() { QMutexLocker locker(&mutex); - connect(ofonoManager,SIGNAL(modemChanged()),this,SLOT(changedModem())); - ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); - ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); - + if (ofonoManager->isValid()) { + Q_FOREACH (const QString &modem, ofonoManager->getModems()) { + QOfonoDataConnectionManagerInterface *ofonoContextManager + = new QOfonoDataConnectionManagerInterface(modem,this); + ofonoContextManagers.insert(modem, ofonoContextManager); + } + } // Get current list of access points. foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { locker.unlock(); @@ -746,11 +750,14 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri } } } else if (connectionType == QLatin1String("gsm")) { - cpPriv->bearerType = currentBearerType(); + + const QString contextPath = map.value("connection").value("id").toString(); + cpPriv->name = contextName(contextPath); + cpPriv->bearerType = currentBearerType(contextPath); + if (map.value("connection").contains("timestamp")) { cpPriv->state |= QNetworkConfiguration::Discovered; } - cpPriv->name = contextName(map.value("connection").value("id").toString()); } return cpPriv; @@ -889,34 +896,32 @@ QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration( return QNetworkConfigurationPrivatePointer(); } -void QNetworkManagerEngine::changedModem() +QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const QString &id) { - if (ofonoNetwork) - delete ofonoNetwork; + if (ofonoManager->isValid()) { + QString contextPart = id.section('/', -1); - ofonoNetwork = new QOfonoNetworkRegistrationInterface(ofonoManager->currentModem(),this); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + QString contextPath = i.key() +"/"+contextPart; + if (i.value()->contexts().contains(contextPath)) { - if (ofonoContextManager) - delete ofonoContextManager; - ofonoContextManager = new QOfonoDataConnectionManagerInterface(ofonoManager->currentModem(),this); -} - -QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType() -{ - if (ofonoContextManager) { - QString bearer = ofonoContextManager->bearer(); - if (bearer == QLatin1String("gsm")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QLatin1String("edge")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QLatin1String("umts")) { - return QNetworkConfiguration::BearerWCDMA; - } else if (bearer == QLatin1String("hspa") - || bearer == QLatin1String("hsdpa") - || bearer == QLatin1String("hsupa")) { - return QNetworkConfiguration::BearerHSPA; - } else if (bearer == QLatin1String("lte")) { - return QNetworkConfiguration::BearerLTE; + QString bearer = i.value()->bearer(); + if (bearer == QStringLiteral("gsm")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("edge")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("umts")) { + return QNetworkConfiguration::BearerWCDMA; + } else if (bearer == QStringLiteral("hspa") + || bearer == QStringLiteral("hsdpa") + || bearer == QStringLiteral("hsupa")) { + return QNetworkConfiguration::BearerHSPA; + } else if (bearer == QStringLiteral("lte")) { + return QNetworkConfiguration::BearerLTE; + } + } } } return QNetworkConfiguration::BearerUnknown; @@ -924,13 +929,16 @@ QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType() QString QNetworkManagerEngine::contextName(const QString &path) { - if (ofonoContextManager) { + if (ofonoManager->isValid()) { QString contextPart = path.section('/', -1); - - Q_FOREACH (const QString &oContext, ofonoContextManager->contexts()) { - if (oContext.contains(contextPart)) { - QOfonoConnectionContextInterface contextInterface(oContext,this); - return contextInterface.name(); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + Q_FOREACH (const QString &oContext, i.value()->contexts()) { + if (oContext.contains(contextPart)) { + QOfonoConnectionContextInterface contextInterface(oContext,this); + return contextInterface.name(); + } } } } diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index d2ef9886a3..84c0b21b6c 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -106,7 +106,6 @@ private Q_SLOTS: void newAccessPoint(const QString &path); void removeAccessPoint(const QString &path); void scanFinished(); - void changedModem(); private: QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath, @@ -125,9 +124,8 @@ private: QHash connectionInterfaces; // ac, interface QOfonoManagerInterface *ofonoManager; - QOfonoNetworkRegistrationInterface *ofonoNetwork; - QOfonoDataConnectionManagerInterface *ofonoContextManager; - QNetworkConfiguration::BearerType currentBearerType(); + QHash ofonoContextManagers; + QNetworkConfiguration::BearerType currentBearerType(const QString &id); QString contextName(const QString &path); }; From 8a81319be1d0d9ceadc1b4f17a707c6db08dd280 Mon Sep 17 00:00:00 2001 From: MihailNaydenov Date: Fri, 3 Oct 2014 15:37:13 +0300 Subject: [PATCH 177/323] Fix loading 2x images in Rich Text Documents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some issues preventing 2x images from loading, mainly incorrect testing for exist() by passing an url, which always reports ‘false’. Task-number: QTBUG-36383 Change-Id: I1e8e5a91b01f1a4ddd3559c2e860db5bc41908ce Reviewed-by: Morten Johan Sørvig --- src/gui/text/qtextimagehandler.cpp | 67 ++++++++++++++++++------------ 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp index f6525448de..37c18e3624 100644 --- a/src/gui/text/qtextimagehandler.cpp +++ b/src/gui/text/qtextimagehandler.cpp @@ -44,31 +44,49 @@ QT_BEGIN_NAMESPACE -static QString resolve2xFile(const QString &fileName, qreal targetDevicePixelRatio) +static QString resolveFileName(QString fileName, QUrl *url, qreal targetDevicePixelRatio) { + // We might use the fileName for loading if url loading fails + // try to make sure it is a valid file path. + // Also, QFile{Info}::exists works only on filepaths (not urls) + + if (url->isValid()) { + if (url->scheme() == QLatin1Literal("qrc")) { + fileName = fileName.right(fileName.length() - 3); + } + else if (url->scheme() == QLatin1Literal("file")) { + fileName = url->toLocalFile(); + } + } + if (targetDevicePixelRatio <= 1.0) return fileName; - int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); + // try to find a 2x version + + const int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); if (dotIndex != -1) { QString at2xfileName = fileName; at2xfileName.insert(dotIndex, QStringLiteral("@2x")); - if (QFile::exists(at2xfileName)) - return at2xfileName; + if (QFile::exists(at2xfileName)) { + fileName = at2xfileName; + *url = QUrl(fileName); + } } + return fileName; } -static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format) + +static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0) { QPixmap pm; QString name = format.name(); - if (name.startsWith(QLatin1String(":/"))) // auto-detect resources + if (name.startsWith(QLatin1String(":/"))) // auto-detect resources and convert them to url name.prepend(QLatin1String("qrc")); - QPaintDevice *pdev = doc->documentLayout()->paintDevice(); - name = resolve2xFile(name, pdev ? pdev->devicePixelRatio() : qApp->devicePixelRatio()); QUrl url = QUrl(name); + name = resolveFileName(name, &url, devicePixelRatio); const QVariant data = doc->resource(QTextDocument::ImageResource, url); if (data.type() == QVariant::Pixmap || data.type() == QVariant::Image) { pm = qvariant_cast(data); @@ -77,19 +95,18 @@ static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format) } if (pm.isNull()) { - QString context; #if 0 + QString context; // ### Qt5 QTextBrowser *browser = qobject_cast(doc->parent()); if (browser) context = browser->source().toString(); #endif + // try direct loading QImage img; - if (img.isNull()) { // try direct loading - name = format.name(); // remove qrc:/ prefix again - if (name.isEmpty() || !img.load(name)) - return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png")); - } + if (name.isEmpty() || !img.load(name)) + return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png")); + pm = QPixmap::fromImage(img); doc->addResource(QTextDocument::ImageResource, url, pm); } @@ -142,16 +159,15 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format) return size; } -static QImage getImage(QTextDocument *doc, const QTextImageFormat &format) +static QImage getImage(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0) { QImage image; QString name = format.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); - QPaintDevice *pdev = doc->documentLayout()->paintDevice(); - name = resolve2xFile(name, pdev ? pdev->devicePixelRatio() : qApp->devicePixelRatio()); QUrl url = QUrl(name); + name = resolveFileName(name, &url, devicePixelRatio); const QVariant data = doc->resource(QTextDocument::ImageResource, url); if (data.type() == QVariant::Image) { image = qvariant_cast(data); @@ -160,19 +176,18 @@ static QImage getImage(QTextDocument *doc, const QTextImageFormat &format) } if (image.isNull()) { - QString context; - #if 0 + QString context; // ### Qt5 QTextBrowser *browser = qobject_cast(doc->parent()); if (browser) context = browser->source().toString(); #endif - if (image.isNull()) { // try direct loading - name = format.name(); // remove qrc:/ prefix again - if (name.isEmpty() || !image.load(name)) - return QImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png")); - } + // try direct loading + + if (name.isEmpty() || !image.load(name)) + return QImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png")); + doc->addResource(QTextDocument::ImageResource, url, image); } @@ -241,10 +256,10 @@ void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocumen const QTextImageFormat imageFormat = format.toImageFormat(); if (QCoreApplication::instance()->thread() != QThread::currentThread()) { - const QImage image = getImage(doc, imageFormat); + const QImage image = getImage(doc, imageFormat, p->device()->devicePixelRatio()); p->drawImage(rect, image, image.rect()); } else { - const QPixmap pixmap = getPixmap(doc, imageFormat); + const QPixmap pixmap = getPixmap(doc, imageFormat, p->device()->devicePixelRatio()); p->drawPixmap(rect, pixmap, pixmap.rect()); } } From a61247723a7b8b371a7328d1d7ec5ca4a5ff3d84 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 7 Nov 2014 14:05:41 +1000 Subject: [PATCH 178/323] Make QtBearer networkmanager backend respond to wired cabling changes Cabling changes can be detected right away, so we should act on that and change the configuration state. Change-Id: Ifa9709077215567001e11ab655208a2c1b090073 Reviewed-by: Alex Blasche --- .../networkmanager/qnetworkmanagerengine.cpp | 128 +++++++++++++----- .../networkmanager/qnetworkmanagerengine.h | 4 + .../networkmanager/qnetworkmanagerservice.cpp | 30 +++- .../networkmanager/qnetworkmanagerservice.h | 4 +- 4 files changed, 124 insertions(+), 42 deletions(-) diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 9adadb8f4f..6be682878d 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -98,6 +98,9 @@ QNetworkManagerEngine::~QNetworkManagerEngine() qDeleteAll(ofonoContextManagers); ofonoContextManagers.clear(); + + qDeleteAll(wiredDevices); + wiredDevices.clear(); } void QNetworkManagerEngine::initialize() @@ -111,13 +114,6 @@ void QNetworkManagerEngine::initialize() ofonoContextManagers.insert(modem, ofonoContextManager); } } - // Get current list of access points. - foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { - locker.unlock(); - deviceAdded(devicePath); //add all accesspoints - locker.relock(); - } - // Get active connections. foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { @@ -128,13 +124,20 @@ void QNetworkManagerEngine::initialize() this, SLOT(activeConnectionPropertiesChanged(QMap))); activeConnection->setConnections(); - QList devices = activeConnection->devices(); + QStringList devices = activeConnection->devices(); if (!devices.isEmpty()) { - QNetworkManagerInterfaceDevice device(devices.at(0).path(),this); + QNetworkManagerInterfaceDevice device(devices.at(0),this); connectionInterfaces.insert(activeConnection->connection().path(),device.networkInterface()); } } + // Get current list of access points. + foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { + locker.unlock(); + deviceAdded(devicePath); //add all accesspoints + locker.relock(); + } + // Get connections. foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) { locker.unlock(); @@ -338,9 +341,9 @@ void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMapmutex.lock(); if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - QList devices = activeConnection->devices(); + QStringList devices = activeConnection->devices(); if (!devices.isEmpty()) { - QNetworkManagerInterfaceDevice device(devices.at(0).path(),this); + QNetworkManagerInterfaceDevice device(devices.at(0),this); connectionInterfaces.insert(id,device.networkInterface()); } @@ -405,6 +408,13 @@ void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) wirelessDevices.insert(path.path(), wirelessDevice); } + + if (iDevice->deviceType() == DEVICE_TYPE_ETHERNET) { + QNetworkManagerInterfaceDeviceWired *wiredDevice = + new QNetworkManagerInterfaceDeviceWired(iDevice->connectionInterface()->path(),this); + connect(wiredDevice,SIGNAL(carrierChanged(bool)),this,SLOT(wiredCarrierChanged(bool))); + wiredDevices.insert(iDevice->connectionInterface()->path(), wiredDevice); + } } void QNetworkManagerEngine::deviceRemoved(const QDBusObjectPath &path) @@ -421,6 +431,41 @@ void QNetworkManagerEngine::deviceRemoved(const QDBusObjectPath &path) delete wirelessDevices.take(path.path()); locker.relock(); } + if (wiredDevices.contains(path.path())) { + locker.unlock(); + delete wiredDevices.take(path.path()); + locker.relock(); + } +} + +void QNetworkManagerEngine::wiredCarrierChanged(bool carrier) +{ + QNetworkManagerInterfaceDeviceWired *deviceWired = qobject_cast(sender()); + if (!deviceWired) + return; + QMutexLocker locker(&mutex); + foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) { + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + if (connection->getType() == DEVICE_TYPE_ETHERNET + && settingsPath.path() == connection->connectionInterface()->path()) { + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(settingsPath.path()); + + if (ptr) { + ptr->mutex.lock(); + if (carrier) + ptr->state |= QNetworkConfiguration::Discovered; + else + ptr->state = QNetworkConfiguration::Defined; + ptr->mutex.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + return; + } + } + } + } } void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, @@ -437,32 +482,37 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, QNetworkManagerSettingsConnection *connection = new QNetworkManagerSettingsConnection(settings->connectionInterface()->service(), path.path(),this); - QString apPath; - for (int i = 0; i < accessPoints.count(); ++i) { - if (connection->getSsid() == accessPoints.at(i)->ssid()) { - // remove the corresponding accesspoint from configurations - apPath = accessPoints.at(i)->connectionInterface()->path(); - - QNetworkConfigurationPrivatePointer ptr - = accessPointConfigurations.take(apPath); - if (ptr) { - locker.unlock(); - emit configurationRemoved(ptr); - locker.relock(); - } - } + const QString settingsPath = connection->connectionInterface()->path(); + if (accessPointConfigurations.contains(settingsPath)) { + return; } + connections.append(connection); connect(connection,SIGNAL(removed(QString)),this,SLOT(removeConnection(QString))); connect(connection,SIGNAL(updated()),this,SLOT(updateConnection())); connection->setConnections(); - const QString settingsPath = connection->connectionInterface()->path(); + NMDeviceType deviceType = connection->getType(); - if (connection->getType() == DEVICE_TYPE_WIFI - && !configuredAccessPoints.contains(settingsPath)) - configuredAccessPoints.insert(apPath,settingsPath); + if (deviceType == DEVICE_TYPE_WIFI) { + QString apPath; + for (int i = 0; i < accessPoints.count(); ++i) { + if (connection->getSsid() == accessPoints.at(i)->ssid()) { + // remove the corresponding accesspoint from configurations + apPath = accessPoints.at(i)->connectionInterface()->path(); + QNetworkConfigurationPrivatePointer ptr + = accessPointConfigurations.take(apPath); + if (ptr) { + locker.unlock(); + emit configurationRemoved(ptr); + locker.relock(); + } + } + } + if (!configuredAccessPoints.contains(settingsPath)) + configuredAccessPoints.insert(apPath,settingsPath); + } QNetworkConfigurationPrivate *cpPriv = parseConnection(settingsPath, connection->getSettings()); @@ -476,9 +526,21 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, break; } } + if (deviceType == DEVICE_TYPE_ETHERNET) { + QHashIterator i(interfaceDevices); + while (i.hasNext()) { + i.next(); + if (i.value()->deviceType() == deviceType) { + QNetworkManagerInterfaceDeviceWired *wiredDevice + = wiredDevices.value(i.value()->connectionInterface()->path()); + if (wiredDevice->carrier()) { + cpPriv->state |= QNetworkConfiguration::Discovered; + } + } + } + } QNetworkConfigurationPrivatePointer ptr(cpPriv); accessPointConfigurations.insert(ptr->id, ptr); - locker.unlock(); emit configurationAdded(ptr); } @@ -524,8 +586,6 @@ void QNetworkManagerEngine::updateConnection() qobject_cast(sender()); if (!connection) return; - - connection->deleteLater(); const QString settingsPath = connection->connectionInterface()->path(); QNetworkConfigurationPrivate *cpPriv = parseConnection(settingsPath, connection->getSettings()); @@ -718,8 +778,8 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri foreach (const QDBusObjectPath &devicePath, managerInterface->getDevices()) { QNetworkManagerInterfaceDevice device(devicePath.path(),this); if (device.deviceType() == DEVICE_TYPE_ETHERNET) { - QNetworkManagerInterfaceDeviceWired wiredDevice(device.connectionInterface()->path(),this); - if (wiredDevice.carrier()) { + QNetworkManagerInterfaceDeviceWired *wiredDevice = wiredDevices.value(device.connectionInterface()->path()); + if (wiredDevice->carrier()) { cpPriv->state |= QNetworkConfiguration::Discovered; break; } diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index 84c0b21b6c..671ed80dab 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -107,6 +107,8 @@ private Q_SLOTS: void removeAccessPoint(const QString &path); void scanFinished(); + void wiredCarrierChanged(bool); + private: QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath, const QNmSettingsMap &map); @@ -114,7 +116,9 @@ private: QNetworkManagerInterface *managerInterface; QNetworkManagerSettings *systemSettings; + QHash wiredDevices; QHash wirelessDevices; + QHash activeConnectionsList; QList connections; QList accessPoints; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index 2d54fa3029..dd7000bfb8 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -609,12 +609,32 @@ bool QNetworkManagerInterfaceDeviceWired::carrier() const return false; } +QStringList QNetworkManagerInterfaceDeviceWired::availableConnections() +{ + QStringList list; + if (propertyMap.contains("AvailableConnections")) { + const QDBusArgument &dbusArgs = propertyMap.value("Carrier").value(); + QDBusObjectPath path; + dbusArgs.beginArray(); + while (!dbusArgs.atEnd()) { + dbusArgs >> path; + list << path.path(); + } + dbusArgs.endArray(); + } + + return list; +} + void QNetworkManagerInterfaceDeviceWired::propertiesSwap(QMap map) { QMapIterator i(map); while (i.hasNext()) { i.next(); propertyMap.insert(i.key(),i.value()); + if (i.key() == QStringLiteral("Carrier")) { + Q_EMIT carrierChanged(i.value().toBool()); + } } Q_EMIT propertiesChanged(map); } @@ -1231,24 +1251,20 @@ QDBusObjectPath QNetworkManagerConnectionActive::specificObject() const return QDBusObjectPath(); } -QList QNetworkManagerConnectionActive::devices() const +QStringList QNetworkManagerConnectionActive::devices() const { + QStringList list; if (propertyMap.contains("Devices")) { const QDBusArgument &dbusArgs = propertyMap.value("Devices").value(); QDBusObjectPath path; - QList list; dbusArgs.beginArray(); while (!dbusArgs.atEnd()) { dbusArgs >> path; - list.append(path); + list.append(path.path()); } dbusArgs.endArray(); - - return list; } - QList list; - list << QDBusObjectPath(); return list; } diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index df4e5d49e1..5e3c1c85f1 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -305,10 +305,12 @@ public: bool carrier() const; bool setConnections(); bool isValid(); + QStringList availableConnections(); Q_SIGNALS: void propertiesChanged(QMap); void propertiesReady(); + void carrierChanged(bool); private Q_SLOTS: void propertiesSwap(QMap); @@ -494,7 +496,7 @@ public: QDBusInterface *connectionInterface() const; QDBusObjectPath connection() const; QDBusObjectPath specificObject() const; - QList devices() const; + QStringList devices() const; quint32 state() const; bool defaultRoute() const; bool setConnections(); From 7a593e0d00abd0d8930fd7cdd8334a42fca7da6d Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Fri, 7 Nov 2014 15:38:32 +1000 Subject: [PATCH 179/323] make qtbearer networkmanager defaultConfiguration more reliable The defaultConfiguration could switch and be either active connection, so we determine the default should be what has the default route. Change-Id: I194f27b60e7a3598eca2ff09c2225ba1a46564d9 Reviewed-by: Alex Blasche --- .../bearer/networkmanager/qnetworkmanagerengine.cpp | 9 +++++++++ .../bearer/networkmanager/qnetworkmanagerservice.cpp | 7 +++++++ .../bearer/networkmanager/qnetworkmanagerservice.h | 1 + 3 files changed, 17 insertions(+) diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index 6be682878d..a8244f05cf 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -953,6 +953,15 @@ QNetworkSessionPrivate *QNetworkManagerEngine::createSessionBackend() QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration() { + QHashIterator i(activeConnectionsList); + while (i.hasNext()) { + i.next(); + QNetworkManagerConnectionActive *activeConnection = i.value(); + if ((activeConnection->defaultRoute() || activeConnection->default6Route())) { + return accessPointConfigurations.value(activeConnection->connection().path()); + } + } + return QNetworkConfigurationPrivatePointer(); } diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index dd7000bfb8..dc3b71ec8e 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -1282,6 +1282,13 @@ bool QNetworkManagerConnectionActive::defaultRoute() const return false; } +bool QNetworkManagerConnectionActive::default6Route() const +{ + if (propertyMap.contains("Default6")) + return propertyMap.value("Default6").toBool(); + return false; +} + void QNetworkManagerConnectionActive::propertiesSwap(QMap map) { QMapIterator i(map); diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index 5e3c1c85f1..da909c443a 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -499,6 +499,7 @@ public: QStringList devices() const; quint32 state() const; bool defaultRoute() const; + bool default6Route() const; bool setConnections(); bool isValid(); From 2f7d0838b8fd338b20eb7059caf6bc5fba6e5266 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Mon, 3 Nov 2014 17:44:50 +0100 Subject: [PATCH 180/323] WinRT: Add missing manifest specifier for rotation Add WINRT_MANIFEST.rotation_preference as description which orientation is allowed or preferred by the app. Valid values for Windows Phone are portrait, landscape, landscapeFlipped. WinRT also allows portraitFlipped Task-number: QTBUG-40830 Change-Id: I6b11afcdb72c2c158dadddafc5d90c1d18ab9d8b Reviewed-by: Andrew Knight --- .../manifests/8.1/AppxManifest.xml.in | 2 +- .../manifests/8.1_wp/AppxManifest.xml.in | 2 +- mkspecs/features/winrt/package_manifest.prf | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in index 97d3407403..a6fc9697f4 100644 --- a/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in +++ b/mkspecs/common/winrt_winphone/manifests/8.1/AppxManifest.xml.in @@ -34,7 +34,7 @@ - + $${WINRT_MANIFEST.rotation_preference} $${WINRT_MANIFEST.capabilities}$${WINRT_MANIFEST.dependencies} diff --git a/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in b/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in index cf18a4dc79..b75570ad4e 100644 --- a/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in +++ b/mkspecs/common/winrt_winphone/manifests/8.1_wp/AppxManifest.xml.in @@ -37,7 +37,7 @@ - + $${WINRT_MANIFEST.rotation_preference} $${WINRT_MANIFEST.capabilities}$${WINRT_MANIFEST.dependencies} diff --git a/mkspecs/features/winrt/package_manifest.prf b/mkspecs/features/winrt/package_manifest.prf index b4242bfdaa..2ccb5db963 100644 --- a/mkspecs/features/winrt/package_manifest.prf +++ b/mkspecs/features/winrt/package_manifest.prf @@ -24,6 +24,7 @@ # WINRT_MANIFEST.logo_medium: Medium logo image file. Default provided by the mkspec. # WINRT_MANIFEST.logo_large: Large logo image file. Default provided by the mkspec. # WINRT_MANIFEST.splash_screen: Splash screen image file. Default provided by the mkspec. +# WINRT_MANIFEST.rotation_preference: Orientation specification. Default is empty. (portrait, landscape, landscapeFlipped) # WINRT_MANIFEST.iconic_tile_icon: Image file for the "iconic" tile template icon. Default provided by the mkspec. # WINRT_MANIFEST.iconic_tile_small: Image file for the small "iconic" tile template logo. Default provided by the mkspec. # WINRT_MANIFEST.default_language: Specifies the default language of the application @@ -87,6 +88,20 @@ isEmpty(WINRT_MANIFEST.foreground): WINRT_MANIFEST.foreground = light isEmpty(WINRT_MANIFEST.default_language): WINRT_MANIFEST.default_language = en + INDENT = "$$escape_expand(\\r\\n) " + + VS_XML_NAMESPACE = "m2" + winphone: VS_XML_NAMESPACE = "m3" + WINRT_MANIFEST.rotation_preference = $$unique(WINRT_MANIFEST.rotation_preference) + !isEmpty(WINRT_MANIFEST.rotation_preference) { + MANIFEST_ROTATION += "<$${VS_XML_NAMESPACE}:InitialRotationPreference>" + for(ROTATION, WINRT_MANIFEST.rotation_preference): \ + MANIFEST_ROTATION += " <$${VS_XML_NAMESPACE}:Rotation Preference=\"$$ROTATION\" />" + MANIFEST_ROTATION += "" + + WINRT_MANIFEST.rotation_preference = $$join(MANIFEST_ROTATION, $$INDENT, $$INDENT) + } + INDENT = "$$escape_expand(\\r\\n) " # Capabilities are given as a string list and may change with the configuration (network, sensors, etc.) From b67d853d2c3d9cb3e9be9a62396f5cd97a18c125 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Tue, 4 Nov 2014 12:41:10 +0200 Subject: [PATCH 181/323] Fix crash in QNetworkSession when engine is not set Task-number: QTBUG-42427 Change-Id: Ie35d5e0f72be3a16ecb6b928e12bc50d9f183590 Reviewed-by: Andy Shaw --- src/plugins/bearer/qnetworksession_impl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/bearer/qnetworksession_impl.cpp b/src/plugins/bearer/qnetworksession_impl.cpp index 1db59fec94..c5adc98af7 100644 --- a/src/plugins/bearer/qnetworksession_impl.cpp +++ b/src/plugins/bearer/qnetworksession_impl.cpp @@ -366,7 +366,8 @@ void QNetworkSessionPrivateImpl::networkConfigurationsChanged() else updateStateFromActiveConfig(); - startTime = engine->startTime(activeConfig.identifier()); + if (engine) + startTime = engine->startTime(activeConfig.identifier()); } void QNetworkSessionPrivateImpl::configurationChanged(QNetworkConfigurationPrivatePointer config) From 645f9eec00b63c076cad488c7ec19a5be9e5dd5e Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 3 Nov 2014 20:38:01 +0100 Subject: [PATCH 182/323] QGraphicsItem: clarify the documentation about caching modes and update() It is possible that Qt calls paint() several times for an item that has caching enabled, even without any explicit call to update(). There are various reasons why that is possible (memory pressure, item gets transformed, etc.); the important part is that 1) the user must not rely into "caching enabled" = "1 paint() call" 2) the user must always draw the same content from within paint(), unless update() was called before that call to paint(). Task-number: QTBUG-18410 Change-Id: I2c8d77e6e11aaceffc9a21003dd3f4cc46edd582 Reviewed-by: Venugopal Shivashankar Reviewed-by: Andy Shaw --- src/widgets/graphicsview/qgraphicsitem.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 76a75dfc35..300e2f492b 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -1968,8 +1968,10 @@ QGraphicsItem::CacheMode QGraphicsItem::cacheMode() const Caching can speed up rendering if your item spends a significant time redrawing itself. In some cases the cache can also slow down rendering, in particular when the item spends less time redrawing than QGraphicsItem - spends redrawing from the cache. When enabled, the item's paint() function - will be called only once for each call to update(); for any subsequent + spends redrawing from the cache. + + When caching is enabled, an item's paint() function will generally draw into an + offscreen pixmap cache; for any subsequent repaint requests, the Graphics View framework will redraw from the cache. This approach works particularly well with QGLWidget, which stores all the cache as OpenGL textures. @@ -1980,6 +1982,12 @@ QGraphicsItem::CacheMode QGraphicsItem::cacheMode() const You can read more about the different cache modes in the CacheMode documentation. + \note Enabling caching does not imply that the item's paint() function will be + called only in response to an explicit update() call. For instance, under + memory pressure, Qt may decide to drop some of the cache information; + in such cases an item's paint() function will be called even if there + was no update() call (that is, exactly as if there were no caching enabled). + \sa CacheMode, QPixmapCache::setCacheLimit() */ void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize) @@ -5337,6 +5345,16 @@ void QGraphicsItem::setBoundingRegionGranularity(qreal granularity) All painting is done in local coordinates. + \note It is mandatory that an item will always redraw itself in the exact + same way, unless update() was called; otherwise visual artifacts may + occur. In other words, two subsequent calls to paint() must always produce + the same output, unless update() was called between them. + + \note Enabling caching for an item does not guarantee that paint() + will be invoked only once by the Graphics View framework, + even without any explicit call to update(). See the documentation of + setCacheMode() for more details. + \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption */ From 3d70925ee54d06e90bea392883d230b8ae2b1782 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Fri, 7 Nov 2014 11:04:49 +0200 Subject: [PATCH 183/323] direct2d: Use simple event posting to avoid event queue lock up In rare cases, the Windows event loop can be spinning inside the inner loop and the message hook is never called. This can be triggered on the Direct2D platform by opening 32+ window handles. The issue can be worked around by using the same approach Windows CE uses: don't rely on the message hook to inform the event loop that the post message has been delivered. Instead, uninstall the hook and let it be called directly by the event loop. Task-number: QTBUG-42428 Change-Id: I10280126dd50729bc260aa5f7029549e2e061c01 Reviewed-by: Louai Al-Khanji Reviewed-by: Friedemann Kleint --- src/corelib/kernel/qeventdispatcher_win.cpp | 57 ++++++++++++------- src/corelib/kernel/qeventdispatcher_win_p.h | 2 + .../direct2d/qwindowsdirect2dintegration.cpp | 16 ++++++ .../direct2d/qwindowsdirect2dintegration.h | 1 + 4 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index a3d00faf31..62e6e9f051 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -434,9 +434,10 @@ static inline UINT inputTimerMask() LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) { + QEventDispatcherWin32 *q = qobject_cast(QAbstractEventDispatcher::instance()); + Q_ASSERT(q != 0); + if (wp == PM_REMOVE) { - QEventDispatcherWin32 *q = qobject_cast(QAbstractEventDispatcher::instance()); - Q_ASSERT(q != 0); if (q) { MSG *msg = (MSG *) lp; QEventDispatcherWin32Private *d = q->d_func(); @@ -472,7 +473,7 @@ LRESULT QT_WIN_CALLBACK qt_GetMessageHook(int code, WPARAM wp, LPARAM lp) #ifdef Q_OS_WINCE return 0; #else - return CallNextHookEx(0, code, wp, lp); + return q->d_func()->getMessageHook ? CallNextHookEx(0, code, wp, lp) : 0; #endif } @@ -643,15 +644,7 @@ void QEventDispatcherWin32::createInternalHwnd() return; d->internalHwnd = qt_create_internal_window(this); -#ifndef Q_OS_WINCE - // setup GetMessage hook needed to drive our posted events - d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); - if (!d->getMessageHook) { - int errorCode = GetLastError(); - qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s", - errorCode, qPrintable(qt_error_string(errorCode))); - } -#endif + installMessageHook(); // register all socket notifiers QList sockets = (d->sn_read.keys().toSet() @@ -665,6 +658,35 @@ void QEventDispatcherWin32::createInternalHwnd() d->registerTimer(d->timerVec.at(i)); } +void QEventDispatcherWin32::installMessageHook() +{ + Q_D(QEventDispatcherWin32); + + if (d->getMessageHook) + return; + +#ifndef Q_OS_WINCE + // setup GetMessage hook needed to drive our posted events + d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId()); + if (!d->getMessageHook) { + int errorCode = GetLastError(); + qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s", + errorCode, qPrintable(qt_error_string(errorCode))); + } +#endif +} + +void QEventDispatcherWin32::uninstallMessageHook() +{ + Q_D(QEventDispatcherWin32); + +#ifndef Q_OS_WINCE + if (d->getMessageHook) + UnhookWindowsHookEx(d->getMessageHook); +#endif + d->getMessageHook = 0; +} + QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherWin32Private, parent) { @@ -750,10 +772,9 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } } if (haveMessage) { -#ifdef Q_OS_WINCE // WinCE doesn't support hooks at all, so we have to call this by hand :( - (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); -#endif + if (!d->getMessageHook) + (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg); if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) { if (seenWM_QT_SENDPOSTEDEVENTS) { @@ -1134,11 +1155,7 @@ void QEventDispatcherWin32::closingDown() d->timerVec.clear(); d->timerDict.clear(); -#ifndef Q_OS_WINCE - if (d->getMessageHook) - UnhookWindowsHookEx(d->getMessageHook); - d->getMessageHook = 0; -#endif + uninstallMessageHook(); } bool QEventDispatcherWin32::event(QEvent *e) diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index 369c276615..a68f6cfa28 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -67,6 +67,8 @@ class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher protected: void createInternalHwnd(); + void installMessageHook(); + void uninstallMessageHook(); public: explicit QEventDispatcherWin32(QObject *parent = 0); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index 142362a065..351f94be2b 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -39,6 +39,7 @@ #include "qwindowsdirect2dwindow.h" #include "qwindowscontext.h" +#include "qwindowsguieventdispatcher.h" #include #include @@ -47,6 +48,16 @@ QT_BEGIN_NAMESPACE +class QWindowsDirect2DEventDispatcher : public QWindowsGuiEventDispatcher +{ +public: + QWindowsDirect2DEventDispatcher(QObject *parent = 0) + : QWindowsGuiEventDispatcher(parent) + { + uninstallMessageHook(); // ### Workaround for QTBUG-42428 + } +}; + class QWindowsDirect2DIntegrationPrivate { public: @@ -237,6 +248,11 @@ QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(Q return new QWindowsDirect2DBackingStore(window); } +QAbstractEventDispatcher *QWindowsDirect2DIntegration::createEventDispatcher() const +{ + return new QWindowsDirect2DEventDispatcher; +} + QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const { return &d->m_d2dContext; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h index b410464372..c72b22a6e8 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -56,6 +56,7 @@ public: QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const Q_DECL_OVERRIDE; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; QWindowsDirect2DContext *direct2DContext() const; From 6451c4baeb829708628a5759ee3d3978489acc7d Mon Sep 17 00:00:00 2001 From: Matt Fischer Date: Wed, 15 Oct 2014 09:47:10 -0500 Subject: [PATCH 184/323] Fix release-with-debuginfo flags for QCC Due to the way that the QCC mkspecs are structured, the recent change to add full optimization support causes the -O2 flag to be completely dropped from QCC builds in release-with-debuginfo mode, since the QMAKE_CFLAGS_OPTIMIZE variable is not declared in any configuration file included by QCC toolchains. This patch adds the necessary flags to make the QCC toolchain operate correctly. Change-Id: I4cd93442d59fae7c92fc5219cddb16f367447203 Reviewed-by: Rafael Roquetto --- mkspecs/common/qcc-base.conf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mkspecs/common/qcc-base.conf b/mkspecs/common/qcc-base.conf index 122f940ec3..f529d7fc7b 100644 --- a/mkspecs/common/qcc-base.conf +++ b/mkspecs/common/qcc-base.conf @@ -11,11 +11,15 @@ QMAKE_COMPILER = rim_qcc gcc # qcc is mostly gcc in disguise +QMAKE_CFLAGS_OPTIMIZE = -O2 +QMAKE_CFLAGS_OPTIMIZE_FULL = -O3 + QMAKE_CFLAGS += -Wno-psabi QMAKE_CFLAGS_DEPS += -M QMAKE_CFLAGS_WARN_ON += -Wall -W QMAKE_CFLAGS_WARN_OFF += -w -QMAKE_CFLAGS_RELEASE += -O2 +QMAKE_CFLAGS_RELEASE += $$QMAKE_CFLAGS_OPTIMIZE +QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_OPTIMIZE -g QMAKE_CFLAGS_DEBUG += -g QMAKE_CFLAGS_SHLIB += -fPIC -shared QMAKE_CFLAGS_STATIC_LIB += -fPIC @@ -36,6 +40,7 @@ QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB From 82c2118cba2744000cff7cd3e5e952df775f5aba Mon Sep 17 00:00:00 2001 From: Matt Fischer Date: Tue, 14 Oct 2014 16:57:20 -0500 Subject: [PATCH 185/323] Improve QElapsedTimer resolution on QNX The standard POSIX clock functions are present on QNX, but only return timing information with millisecond accuracy. To get accuracy beyond that, platform-specific functions must be used. Change-Id: I54a0550f1865dbea3c60a86ecd8ad99df3fe42b4 Reviewed-by: Frank Osterfeld Reviewed-by: Bernd Weimer Reviewed-by: Rafael Roquetto --- src/corelib/tools/qelapsedtimer_unix.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qelapsedtimer_unix.cpp b/src/corelib/tools/qelapsedtimer_unix.cpp index 5b26d551a7..9dd5df0266 100644 --- a/src/corelib/tools/qelapsedtimer_unix.cpp +++ b/src/corelib/tools/qelapsedtimer_unix.cpp @@ -35,8 +35,12 @@ #define _POSIX_C_SOURCE 200809L #include "qelapsedtimer.h" -#ifdef Q_OS_VXWORKS +#if defined(Q_OS_VXWORKS) #include "qfunctions_vxworks.h" +#elif defined(Q_OS_QNX) +#include +#include +#include #else #include #include @@ -84,7 +88,18 @@ QT_BEGIN_NAMESPACE * see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html */ -#ifndef CLOCK_REALTIME +#if defined(Q_OS_QNX) +static inline void qt_clock_gettime(clockid_t clock, struct timespec *ts) +{ + // The standard POSIX clock calls only have 1ms accuracy on QNX. To get + // higher accuracy, this platform-specific function must be used instead + quint64 cycles_per_sec = SYSPAGE_ENTRY(qtime)->cycles_per_sec; + quint64 cycles = ClockCycles(); + ts->tv_sec = cycles / cycles_per_sec; + quint64 mod = cycles % cycles_per_sec; + ts->tv_nsec = mod * Q_INT64_C(1000000000) / cycles_per_sec; +} +#elif !defined(CLOCK_REALTIME) # define CLOCK_REALTIME 0 static inline void qt_clock_gettime(int, struct timespec *ts) { From 370d7bf48afb20017852c0c7faff45d40dbf81a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 22 Oct 2014 13:46:35 +0200 Subject: [PATCH 186/323] iOS: Make hide-keyboard gesture use normal UIGestureRecognizer flow Allows us to track state through the normal gesture recognizer states instead of custom variables. Change-Id: I4fe1b370a581132a9bbb8f51f7bee73381b80341 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosinputcontext.mm | 135 ++++++++++++------ 1 file changed, 92 insertions(+), 43 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 25d9f6c421..acdf6d9715 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -46,25 +46,28 @@ #include "qiosglobal.h" #include "qiosintegration.h" #include "qiostextresponder.h" +#include "qiosviewcontroller.h" #include "qioswindow.h" #include "quiview.h" #include #include +// ------------------------------------------------------------------------- + static QUIView *focusView() { return qApp->focusWindow() ? reinterpret_cast(qApp->focusWindow()->winId()) : 0; } -@interface QIOSKeyboardListener : UIGestureRecognizer { +// ------------------------------------------------------------------------- + +@interface QIOSKeyboardListener : UIGestureRecognizer { @public QIOSInputContext *m_context; BOOL m_keyboardVisible; BOOL m_keyboardVisibleAndDocked; - BOOL m_touchPressWhileKeyboardVisible; - BOOL m_keyboardHiddenByGesture; QRectF m_keyboardRect; CGRect m_keyboardEndRect; NSTimeInterval m_duration; @@ -77,13 +80,11 @@ static QUIView *focusView() - (id)initWithQIOSInputContext:(QIOSInputContext *)context { - self = [super initWithTarget:self action:@selector(gestureTriggered)]; + self = [super initWithTarget:self action:@selector(gestureStateChanged:)]; if (self) { m_context = context; m_keyboardVisible = NO; m_keyboardVisibleAndDocked = NO; - m_touchPressWhileKeyboardVisible = NO; - m_keyboardHiddenByGesture = NO; m_duration = 0; m_curve = UIViewAnimationCurveEaseOut; m_viewController = 0; @@ -99,10 +100,9 @@ static QUIView *focusView() Q_ASSERT(m_viewController); // Attach 'hide keyboard' gesture to the window, but keep it disabled when the - // keyboard is not visible. Note that we never trigger the gesture the way it is intended - // since we don't want to cancel touch events and interrupt flicking etc. Instead we use - // the gesture framework more as an event filter and hide the keyboard silently. + // keyboard is not visible. self.enabled = NO; + self.cancelsTouchesInView = NO; self.delaysTouchesEnded = NO; [m_viewController.view.window addGestureRecognizer:self]; } @@ -156,11 +156,19 @@ static QUIView *focusView() // Note that UIKeyboardWillShowNotification is only sendt when the keyboard is docked. m_keyboardVisibleAndDocked = YES; m_keyboardEndRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; - self.enabled = YES; + if (!m_duration) { m_duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; m_curve = UIViewAnimationCurve([[notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] integerValue]); } + + UIResponder *firstResponder = [UIResponder currentFirstResponder]; + if (![firstResponder isKindOfClass:[QIOSTextInputResponder class]]) + return; + + // Enable hide-keyboard gesture + self.enabled = YES; + m_context->scrollToCursor(); } @@ -169,7 +177,7 @@ static QUIView *focusView() // Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked. m_keyboardVisibleAndDocked = NO; m_keyboardEndRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; - if (!m_keyboardHiddenByGesture) { + if (self.state != UIGestureRecognizerStateBegan) { // Only disable the gesture if the hiding of the keyboard was not caused by it. // Otherwise we need to await the final touchEnd callback for doing some clean-up. self.enabled = NO; @@ -202,54 +210,81 @@ static QUIView *focusView() } } -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event -{ - CGPoint p = [[touches anyObject] locationInView:m_viewController.view.window]; - if (CGRectContainsPoint(m_keyboardEndRect, p)) { - m_keyboardHiddenByGesture = YES; - - UIResponder *firstResponder = [UIResponder currentFirstResponder]; - Q_ASSERT([firstResponder isKindOfClass:[QIOSTextInputResponder class]]); - [firstResponder resignFirstResponder]; - } - - [super touchesMoved:touches withEvent:event]; -} +// ------------------------------------------------------------------------- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - Q_ASSERT(m_keyboardVisibleAndDocked); - m_touchPressWhileKeyboardVisible = YES; [super touchesBegan:touches withEvent:event]; + + Q_ASSERT(m_keyboardVisibleAndDocked); + + if ([touches count] != 1) + self.state = UIGestureRecognizerStateFailed; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesMoved:touches withEvent:event]; + + if (self.state != UIGestureRecognizerStatePossible) + return; + + CGPoint touchPoint = [[touches anyObject] locationInView:m_viewController.view.window]; + if (CGRectContainsPoint(m_keyboardEndRect, touchPoint)) + self.state = UIGestureRecognizerStateBegan; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - m_touchPressWhileKeyboardVisible = NO; - [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO]; [super touchesEnded:touches withEvent:event]; + + [self touchesEndedOrCancelled]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - m_touchPressWhileKeyboardVisible = NO; - [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO]; [super touchesCancelled:touches withEvent:event]; + + [self touchesEndedOrCancelled]; } -- (void)touchesEndedPostDelivery +- (void)touchesEndedOrCancelled { - // Do some clean-up _after_ touchEnd has been delivered to QUIView - m_keyboardHiddenByGesture = NO; + // Defer final state change until next runloop iteration, so that Qt + // has a chance to process the final touch events first, before we eg. + // scroll the view. + dispatch_async(dispatch_get_main_queue (), ^{ + // iOS will transition from began to changed by itself + Q_ASSERT(self.state != UIGestureRecognizerStateBegan); + + if (self.state == UIGestureRecognizerStateChanged) + self.state = UIGestureRecognizerStateEnded; + else + self.state = UIGestureRecognizerStateFailed; + }); +} + +- (void)gestureStateChanged:(id)sender +{ + Q_UNUSED(sender); + + if (self.state == UIGestureRecognizerStateBegan) { + qImDebug() << "hide keyboard gesture was triggered"; + UIResponder *firstResponder = [UIResponder currentFirstResponder]; + Q_ASSERT([firstResponder isKindOfClass:[QIOSTextInputResponder class]]); + [firstResponder resignFirstResponder]; + } +} + +- (void)reset +{ + [super reset]; + if (!m_keyboardVisibleAndDocked) { + qImDebug() << "keyboard was hidden, disabling hide-keyboard gesture"; self.enabled = NO; - if (qApp->focusObject()) { - // UI Controls are told to gain focus on touch release. So when the 'hide keyboard' gesture - // finishes, the final touch end can trigger a control to gain focus. This is in conflict with - // the gesture, so we clear focus once more as a work-around. - static_cast(QObjectPrivate::get(qApp->focusWindow()))->clearFocusObject(); - } } else { + qImDebug() << "gesture completed without triggering, scrolling view to cursor"; m_context->scrollToCursor(); } } @@ -353,10 +388,10 @@ void QIOSInputContext::scrollToCursor() if (!isQtApplication()) return; - if (m_keyboardListener->m_touchPressWhileKeyboardVisible) { - // Don't scroll to the cursor if the user is touching the screen. This - // interferes with selection and the 'hide keyboard' gesture. Instead - // we update scrolling upon touchEnd. + if (m_keyboardListener.state == UIGestureRecognizerStatePossible && m_keyboardListener.numberOfTouches == 1) { + // Don't scroll to the cursor if the user is touching the screen and possibly + // trying to trigger the hide-keyboard gesture. + qImDebug() << "preventing scrolling to cursor as we're still waiting for a possible gesture"; return; } @@ -426,6 +461,18 @@ void QIOSInputContext::setFocusObject(QObject *focusObject) { Q_UNUSED(focusObject); + qImDebug() << "new focus object =" << focusObject; + + if (m_keyboardListener.state == UIGestureRecognizerStateChanged) { + // A new focus object may be set as part of delivering touch events to + // application during the hide-keyboard gesture, but we don't want that + // to result in a new object getting focus and bringing the keyboard up + // again. + qImDebug() << "clearing focus object" << focusObject << "as hide-keyboard gesture is active"; + clearCurrentFocusObject(); + return; + } + reset(); if (m_keyboardListener->m_keyboardVisibleAndDocked) @@ -436,6 +483,8 @@ void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) { Q_UNUSED(focusWindow); + qImDebug() << "new focus window =" << focusWindow; + reset(); [m_keyboardListener handleKeyboardRectChanged]; From 719a6fd50d590e819fa541dc5b31661b38537344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Oct 2014 12:54:26 +0100 Subject: [PATCH 187/323] iOS: Allow virtual keyboard to be hidden by QInputMethod::hide() Calling the function has the same effect as dismissing the keyboard using the native keyboard dismiss button or the hide-keyboard gesture, and will result in the QIOSTextInputResponder losing first-responder status and the current focus object being cleared. QtWidgets and other parts of Qt will try to hide the keyboard during focus changes between widgets, which we already take care of when the focus object changes, so we detect the situation and ignore it, by requiring that the current focus object matches the one we've brought up the text responder for. Showing the virtual keyboard is still a no-op, as there is no way to show the virtual keyboard without a focus-object. Change-Id: Iefcb403c2b6d3da8a4df3fcd53bc1244ba9c4d23 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiosinputcontext.h | 3 ++- src/plugins/platforms/ios/qiosinputcontext.mm | 21 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index f07408db81..1f1130f932 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -51,9 +51,10 @@ QT_BEGIN_NAMESPACE struct ImeState { - ImeState() : currentState(0) {} + ImeState() : currentState(0), focusObject(0) {} Qt::InputMethodQueries update(Qt::InputMethodQueries properties); QInputMethodQueryEvent currentState; + QObject *focusObject; }; class QIOSInputContext : public QPlatformInputContext diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index acdf6d9715..072a49c7c5 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -300,8 +300,11 @@ Qt::InputMethodQueries ImeState::update(Qt::InputMethodQueries properties) QInputMethodQueryEvent newState(properties); - if (qApp && qApp->focusObject()) - QCoreApplication::sendEvent(qApp->focusObject(), &newState); + // Update the focus object that the new state is based on + focusObject = qApp ? qApp->focusObject() : 0; + + if (focusObject) + QCoreApplication::sendEvent(focusObject, &newState); Qt::InputMethodQueries updatedProperties; for (uint i = 0; i < (sizeof(Qt::ImQueryAll) * CHAR_BIT); ++i) { @@ -348,11 +351,23 @@ QRectF QIOSInputContext::keyboardRect() const void QIOSInputContext::showInputPanel() { // No-op, keyboard controlled fully by platform based on focus + qImDebug() << "can't show virtual keyboard without a focus object, ignoring"; } void QIOSInputContext::hideInputPanel() { - // No-op, keyboard controlled fully by platform based on focus + if (![m_textResponder isFirstResponder]) { + qImDebug() << "QIOSTextInputResponder is not first responder, ignoring"; + return; + } + + if (qGuiApp->focusObject() != m_imeState.focusObject) { + qImDebug() << "current focus object does not match IM state, likely hiding from focusOut event, so ignoring"; + return; + } + + qImDebug() << "hiding VKB as requested by QInputMethod::hide()"; + [m_textResponder resignFirstResponder]; } void QIOSInputContext::clearCurrentFocusObject() From 5d99beb14e01f490b38fc568806a6ad972ed5dda Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 4 Nov 2014 14:48:20 -0800 Subject: [PATCH 188/323] Place the Qt plugin metadata in a PE-COFF section with MinGW too Commit ec360d7ad90945273c7d96c9a159131dcbcd67c3 made it work for ELF platforms, Apple platforms and for MSVC, but we apparently forgot it for MinGW. This patch corrects that mistake. We won't have the PE-COFF section parser until 5.5, but this will at least making Qt 5.4-built plugins work on the faster case. Change-Id: I51b06837dc321eaa4724c9598293cf85570f67fc Reviewed-by: Lars Knoll --- src/corelib/plugin/qplugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h index 4e9a60504a..c424344c3a 100644 --- a/src/corelib/plugin/qplugin.h +++ b/src/corelib/plugin/qplugin.h @@ -71,7 +71,7 @@ Q_DECLARE_TYPEINFO(QStaticPlugin, Q_PRIMITIVE_TYPE); void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin staticPlugin); -#if defined (Q_OF_ELF) && (defined (Q_CC_GNU) || defined(Q_CC_CLANG)) +#if (defined(Q_OF_ELF) || defined(Q_OS_WIN)) && (defined (Q_CC_GNU) || defined(Q_CC_CLANG)) # define QT_PLUGIN_METADATA_SECTION \ __attribute__ ((section (".qtmetadata"))) __attribute__((used)) #elif defined(Q_OS_MAC) From ba73bde66efa588a74eaaa946e80e9de2b9e2d59 Mon Sep 17 00:00:00 2001 From: Julien Brianceau Date: Fri, 7 Nov 2014 09:41:07 +0100 Subject: [PATCH 189/323] Compile fix for QT_NO_DOCKWIDGET in QtWidgets Change-Id: I4567e4d0e5738c1de74661a325895f9eaa1d06c4 Reviewed-by: Laszlo Agocs --- src/widgets/widgets/qmainwindowlayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp index 1cc7f201ba..8f8642a72a 100644 --- a/src/widgets/widgets/qmainwindowlayout.cpp +++ b/src/widgets/widgets/qmainwindowlayout.cpp @@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_DOCKWIDGET +#ifdef QT_NO_DOCKWIDGET extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); #endif From d9715108c1bf46d3a2b0482d1c9a0f61215a5e0e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 9 Nov 2014 13:01:35 +0100 Subject: [PATCH 190/323] Android 5.0: extract new Switch style attributes Switch_showText specifies whether the on/off text is shown in the thumb and Switch_splitTrack specifies whether the track is clipped underneath the thumb. Change-Id: I03fc6b799fe714e7b6e604328901c8c5a418ca6e Reviewed-by: BogDan Vatra --- .../jar/src/org/qtproject/qt5/android/ExtractStyle.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index b75dbac4b8..1e30e4a580 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1544,6 +1544,11 @@ public class ExtractStyle { json.put("Switch_switchPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_switchPadding"), 0)); json.put("Switch_thumbTextPadding", a.getDimensionPixelSize(getField(styleableClass, "Switch_thumbTextPadding"), 0)); + if (Build.VERSION.SDK_INT >= 21) { + json.put("Switch_showText", a.getBoolean(getField(styleableClass, "Switch_showText"), true)); + json.put("Switch_splitTrack", a.getBoolean(getField(styleableClass, "Switch_splitTrack"), false)); + } + a.recycle(); jsonWriter.name(styleName).value(json); } catch (Exception e) { From 132650e4e0a02786978663b463966054a3fb412d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 9 Nov 2014 15:51:40 +0100 Subject: [PATCH 191/323] Android: extract BitmapDrawable attributes Task-number: QTBUG-42488 Change-Id: Idd70e6300f78d96b044928885e71957daad1f5af Reviewed-by: BogDan Vatra --- .../qtproject/qt5/android/ExtractStyle.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 1e30e4a580..2aeb89d5d5 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -67,6 +67,7 @@ import android.graphics.NinePatch; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.PorterDuff; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ClipDrawable; @@ -820,8 +821,27 @@ public class ExtractStyle { bmp = (Bitmap) drawable; else { - if (drawable instanceof BitmapDrawable) - bmp = ((BitmapDrawable)drawable).getBitmap(); + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable)drawable; + bmp = bitmapDrawable.getBitmap(); + try { + json.put("gravity", bitmapDrawable.getGravity()); + json.put("tileModeX", bitmapDrawable.getTileModeX()); + json.put("tileModeY", bitmapDrawable.getTileModeY()); + if (Build.VERSION.SDK_INT >= 18) { + json.put("antialias", (Boolean) BitmapDrawable.class.getMethod("hasAntiAlias").invoke(bitmapDrawable)); + json.put("mipMap", (Boolean) BitmapDrawable.class.getMethod("hasMipMap").invoke(bitmapDrawable)); + } + if (Build.VERSION.SDK_INT >= 21) { + json.put("tintMode", (PorterDuff.Mode) BitmapDrawable.class.getMethod("getTintMode").invoke(bitmapDrawable)); + ColorStateList tintList = (ColorStateList) BitmapDrawable.class.getMethod("getTint").invoke(bitmapDrawable); + if (tintList != null) + json.put("tintList", getColorStateList(tintList)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } else { if (drawable instanceof ScaleDrawable) From ade8e0fc9b216190328b6fd3375796e82e34c323 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 14 Oct 2014 15:05:23 +0200 Subject: [PATCH 192/323] Add CFBundleIdentifier to the bundle Info.plist's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the current app CFBundleIdentifier support: handle frameworks as well. Add @BUNDLEIDENTIFIER@ placeholder to the OS X info.plist.lib templates. This means the Qt frameworks will now get a valid CFBundleIdentifier entry the same way as app bundles: by extracting the identifier prefix from Xcode settings and appending framework name. Task-number: QTBUG-32896 Change-Id: Ica8f28332a88e37a823c46fca7a2c373157af020 Reviewed-by: Tor Arne Vestbø Reviewed-by: Oswald Buddenhagen --- mkspecs/macx-clang-32/Info.plist.lib | 2 ++ mkspecs/macx-clang/Info.plist.lib | 2 ++ mkspecs/macx-g++-32/Info.plist.lib | 2 ++ mkspecs/macx-g++/Info.plist.lib | 2 ++ mkspecs/macx-g++40/Info.plist.lib | 2 ++ mkspecs/macx-g++42/Info.plist.lib | 2 ++ mkspecs/macx-icc/Info.plist.lib | 2 ++ mkspecs/macx-llvm/Info.plist.lib | 2 ++ qmake/generators/unix/unixmake2.cpp | 22 +++++++++++++--------- 9 files changed, 29 insertions(+), 9 deletions(-) diff --git a/mkspecs/macx-clang-32/Info.plist.lib b/mkspecs/macx-clang-32/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-clang-32/Info.plist.lib +++ b/mkspecs/macx-clang-32/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-clang/Info.plist.lib b/mkspecs/macx-clang/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-clang/Info.plist.lib +++ b/mkspecs/macx-clang/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-g++-32/Info.plist.lib b/mkspecs/macx-g++-32/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-g++-32/Info.plist.lib +++ b/mkspecs/macx-g++-32/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-g++/Info.plist.lib b/mkspecs/macx-g++/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-g++/Info.plist.lib +++ b/mkspecs/macx-g++/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-g++40/Info.plist.lib b/mkspecs/macx-g++40/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-g++40/Info.plist.lib +++ b/mkspecs/macx-g++40/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-g++42/Info.plist.lib b/mkspecs/macx-g++42/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-g++42/Info.plist.lib +++ b/mkspecs/macx-g++42/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-icc/Info.plist.lib b/mkspecs/macx-icc/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-icc/Info.plist.lib +++ b/mkspecs/macx-icc/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/mkspecs/macx-llvm/Info.plist.lib b/mkspecs/macx-llvm/Info.plist.lib index 2a44d1721e..7cbdb9af12 100644 --- a/mkspecs/macx-llvm/Info.plist.lib +++ b/mkspecs/macx-llvm/Info.plist.lib @@ -14,6 +14,8 @@ @TYPEINFO@ CFBundleExecutable @LIBRARY@ + CFBundleIdentifier + @BUNDLEIDENTIFIER@ NOTE Please, do NOT change this file -- It was generated by Qt/QMake. diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index d9b0e10057..8270f02feb 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -814,22 +814,26 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) } commonSedArgs << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" "; + + QString bundlePrefix = project->first("QMAKE_TARGET_BUNDLE_PREFIX").toQString(); + if (bundlePrefix.isEmpty()) + bundlePrefix = "com.yourcompany"; + if (bundlePrefix.endsWith(".")) + bundlePrefix.chop(1); + QString bundleIdentifier = bundlePrefix + "." + var("QMAKE_BUNDLE"); + if (bundleIdentifier.endsWith(".app")) + bundleIdentifier.chop(4); + if (bundleIdentifier.endsWith(".framework")) + bundleIdentifier.chop(10); + commonSedArgs << "-e \"s,@BUNDLEIDENTIFIER@," << bundleIdentifier << ",g\" "; + if (isApp) { QString icon = fileFixify(var("ICON")); - QString bundlePrefix = project->first("QMAKE_TARGET_BUNDLE_PREFIX").toQString(); - if (bundlePrefix.isEmpty()) - bundlePrefix = "com.yourcompany"; - if (bundlePrefix.endsWith(".")) - bundlePrefix.chop(1); - QString bundleIdentifier = bundlePrefix + "." + var("QMAKE_BUNDLE"); - if (bundleIdentifier.endsWith(".app")) - bundleIdentifier.chop(4); t << "@$(DEL_FILE) " << info_plist_out << "\n\t" << "@sed "; foreach (const ProString &arg, commonSedArgs) t << arg; t << "-e \"s,@ICON@," << icon.section(Option::dir_sep, -1) << ",g\" " - << "-e \"s,@BUNDLEIDENTIFIER@," << bundleIdentifier << ",g\" " << "-e \"s,@EXECUTABLE@," << var("QMAKE_ORIG_TARGET") << ",g\" " << "-e \"s,@TYPEINFO@,"<< (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << ",g\" " From 014785d8533f9fe021edfe5075a3c89494f0fe8d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 10 Nov 2014 14:26:34 +0100 Subject: [PATCH 193/323] tst_QTimer::singleShotToFunctors: Allocate static event loop on heap. Fix warning: QEventLoop: Cannot be used without QApplication and occasional crashes on Windows. Task-number: QTBUG-26406 Change-Id: Ia8b2a4e3d375d1e43f0e66fe64a39af5f9cf4d60 Reviewed-by: Olivier Goffart Reviewed-by: Dario Freddi --- .../auto/corelib/kernel/qtimer/tst_qtimer.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 78c75b44e8..5833123dfe 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -642,18 +642,25 @@ struct CountedStruct QThread *thread; }; -static QEventLoop _e; +static QScopedPointer _e; static QThread *_t = Q_NULLPTR; class StaticEventLoop { public: - static void quitEventLoop() { _e.quit(); if (_t) QCOMPARE(QThread::currentThread(), _t); } + static void quitEventLoop() + { + QVERIFY(!_e.isNull()); + _e->quit(); + if (_t) + QCOMPARE(QThread::currentThread(), _t); + } }; void tst_QTimer::singleShotToFunctors() { int count = 0; + _e.reset(new QEventLoop); QEventLoop e; QTimer::singleShot(0, CountedStruct(&count)); @@ -661,7 +668,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(count, 1); QTimer::singleShot(0, &StaticEventLoop::quitEventLoop); - QCOMPARE(_e.exec(), 0); + QCOMPARE(_e->exec(), 0); QThread t1; QObject c1; @@ -687,7 +694,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(e.exec(), 0); QTimer::singleShot(0, &c2, &StaticEventLoop::quitEventLoop); - QCOMPARE(_e.exec(), 0); + QCOMPARE(_e->exec(), 0); _t->quit(); _t->wait(); @@ -721,8 +728,10 @@ void tst_QTimer::singleShotToFunctors() thread.quit(); thread.wait(); #endif -} + _e.reset(); + _t = Q_NULLPTR; +} class DontBlockEvents : public QObject { From 4e1396690a53069ab0a493fdc1e6a767146a3e1d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 7 Nov 2014 12:10:09 +0100 Subject: [PATCH 194/323] windowsfontengine.cpp: Fix coding style violation and warning. In function 'bool addGlyphToPath(glyph_t, const QFixedPont&, HDC, QPainterPath*, bool, glyph_metrics_t*, qreal)': windowsfontengine.cpp:808:17: warning: comparison between signed and unsigned iteger expressions [-Wsign-compare] if (res == GDI_ERROR) { Introduced by 4aba2d07d2fe67beaf544a4b38c5b9aa8b8ec39b . Change-Id: Ie4d903e65ff45461af5ede18efe8e3c6c12af7e6 Task-number: QTBUG-12799 Reviewed-by: Nicolas Froment Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsfontengine.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index cfa5914ff8..d8ccb8cd56 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -804,10 +804,8 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc, uint format = GGO_METRICS; if (ttf) format |= GGO_GLYPH_INDEX; - int res = GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat); - if (res == GDI_ERROR) { + if (GetGlyphOutline(hdc, glyph, format, &gMetric, 0, 0, &mat) == GDI_ERROR) return false; - } // #### obey scale *metric = glyph_metrics_t(gMetric.gmptGlyphOrigin.x, -gMetric.gmptGlyphOrigin.y, (int)gMetric.gmBlackBoxX, (int)gMetric.gmBlackBoxY, From 7231e1fbe24102f2a93b34dfa70e3dca884440d2 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Wed, 29 Oct 2014 08:06:51 +0100 Subject: [PATCH 195/323] Add changelog entry for Exif orientation Change-Id: I5c7218bad624ff5a834153091f06aa6ffed612b6 Reviewed-by: aavit --- dist/changes-5.4.0 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/changes-5.4.0 b/dist/changes-5.4.0 index 927ca0f9f1..b549d5ded1 100644 --- a/dist/changes-5.4.0 +++ b/dist/changes-5.4.0 @@ -25,6 +25,10 @@ QtCore - Added QEnableSharedFromThis, a class that allows obtaining a QSharedPointer for an object already managed by a shared pointer. +QtGui +----- + + - QImageReader now automatically rotates JPEG images according to Exif orientation QtSql ----- From a7111c5ddef3072eb73c08f14823343208c18f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 30 Oct 2014 16:53:18 +0100 Subject: [PATCH 196/323] Make the -nograb and -dograb arguments actually work on xcb Change-Id: Idc725443e4abe27db3e530f08173897bfcbe1278 Reviewed-by: Friedemann Kleint --- src/gui/kernel/qguiapplication.cpp | 25 ----------- src/gui/kernel/qguiapplication_p.h | 1 - src/gui/kernel/qwindow.cpp | 4 -- src/plugins/platforms/xcb/qxcbconnection.h | 1 + src/plugins/platforms/xcb/qxcbintegration.cpp | 41 ++++++++++++++----- src/plugins/platforms/xcb/qxcbintegration.h | 1 + src/plugins/platforms/xcb/qxcbwindow.cpp | 6 +++ 7 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 59bcd37251..fe92ead846 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -163,7 +163,6 @@ QWindow *QGuiApplicationPrivate::focus_window = 0; static QBasicMutex applicationFontMutex; QFont *QGuiApplicationPrivate::app_font = 0; bool QGuiApplicationPrivate::obey_desktop_settings = true; -bool QGuiApplicationPrivate::noGrab = false; static qreal fontSmoothingGamma = 1.7; @@ -1196,20 +1195,10 @@ void QGuiApplicationPrivate::eventDispatcherReady() platform_integration->initialize(); } -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) -// Find out if our parent process is gdb by looking at the 'exe' symlink under /proc. -static bool runningUnderDebugger() -{ - const QFileInfo parentProcExe(QStringLiteral("/proc/") + QString::number(getppid()) + QStringLiteral("/exe")); - return parentProcExe.isSymLink() && parentProcExe.symLinkTarget().endsWith(QLatin1String("/gdb")); -} -#endif - void QGuiApplicationPrivate::init() { QCoreApplicationPrivate::is_app_running = false; // Starting up. - bool doGrabUnderDebugger = false; bool loadTestability = false; QList pluginList; // Get command line params @@ -1244,10 +1233,6 @@ void QGuiApplicationPrivate::init() QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2)); } #endif - } else if (arg == "-nograb") { - QGuiApplicationPrivate::noGrab = true; - } else if (arg == "-dograb") { - doGrabUnderDebugger = true; #ifndef QT_NO_SESSIONMANAGER } else if (arg == "-session" && i < argc-1) { ++i; @@ -1273,16 +1258,6 @@ void QGuiApplicationPrivate::init() argc = j; } -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) - if (!doGrabUnderDebugger && !QGuiApplicationPrivate::noGrab && runningUnderDebugger()) { - QGuiApplicationPrivate::noGrab = true; - qDebug("Qt: gdb: -nograb added to command-line options.\n" - "\t Use the -dograb option to enforce grabbing."); - } -#else - Q_UNUSED(doGrabUnderDebugger) -#endif - // Load environment exported generic plugins foreach (const QByteArray &plugin, qgetenv("QT_QPA_GENERIC_PLUGINS").split(',')) pluginList << plugin; diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 8988bd461d..eed3d5c10e 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -221,7 +221,6 @@ public: QStyleHints *styleHints; static bool obey_desktop_settings; - static bool noGrab; QInputMethod *inputMethod; QString firstWindowTitle; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 99bf469f87..c6dd0955aa 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1639,8 +1639,6 @@ QPlatformSurface *QWindow::surfaceHandle() const bool QWindow::setKeyboardGrabEnabled(bool grab) { Q_D(QWindow); - if (grab && QGuiApplicationPrivate::noGrab) - return false; if (d->platformWindow) return d->platformWindow->setKeyboardGrabEnabled(grab); return false; @@ -1658,8 +1656,6 @@ bool QWindow::setKeyboardGrabEnabled(bool grab) bool QWindow::setMouseGrabEnabled(bool grab) { Q_D(QWindow); - if (grab && QGuiApplicationPrivate::noGrab) - return false; if (d->platformWindow) return d->platformWindow->setMouseGrabEnabled(grab); return false; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index f31ecf8e03..7286b6b89b 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -471,6 +471,7 @@ public: QXcbEventReader *eventReader() const { return m_reader; } + bool canGrab() const { return m_canGrabServer; } protected: bool event(QEvent *e) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 52269bafea..cace087613 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -92,11 +92,11 @@ QT_BEGIN_NAMESPACE -#if defined(QT_DEBUG) && defined(Q_OS_LINUX) // Find out if our parent process is gdb by looking at the 'exe' symlink under /proc,. // or, for older Linuxes, read out 'cmdline'. static bool runningUnderDebugger() { +#if defined(QT_DEBUG) && defined(Q_OS_LINUX) const QString parentProc = QLatin1String("/proc/") + QString::number(getppid()); const QFileInfo parentProcExe(parentProc + QLatin1String("/exe")); if (parentProcExe.isSymLink()) @@ -113,12 +113,15 @@ static bool runningUnderDebugger() s += c; } return s == "gdb"; -} +#else + return false; #endif +} QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char **argv) : m_services(new QGenericUnixServices) , m_instanceName(0) + , m_canGrab(true) { qRegisterMetaType(); #ifdef XCB_USE_XLIB @@ -126,16 +129,10 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char #endif m_nativeInterface.reset(new QXcbNativeInterface); - bool canGrab = true; - #if defined(QT_DEBUG) && defined(Q_OS_LINUX) - canGrab = !runningUnderDebugger(); - #endif - static bool canNotGrabEnv = qgetenv("QT_XCB_NO_GRAB_SERVER").length(); - if (canNotGrabEnv) - canGrab = false; - // Parse arguments const char *displayName = 0; + bool noGrabArg = false; + bool doGrabArg = false; if (argc) { int j = 1; for (int i = 1; i < argc; i++) { @@ -146,13 +143,35 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters, int &argc, char displayName = argv[++i]; else if (arg == "-name" && i < argc - 1) m_instanceName = argv[++i]; + else if (arg == "-nograb") + noGrabArg = true; + else if (arg == "-dograb") + doGrabArg = true; else argv[j++] = argv[i]; } argc = j; } // argc - m_connections << new QXcbConnection(m_nativeInterface.data(), canGrab, displayName); + bool underDebugger = runningUnderDebugger(); + if (noGrabArg && doGrabArg && underDebugger) { + qWarning() << "Both -nograb and -dograb command line arguments specified. Please pick one. -nograb takes prcedence"; + doGrabArg = false; + } + +#if defined(QT_DEBUG) + if (!noGrabArg && !doGrabArg && underDebugger) { + qDebug("Qt: gdb: -nograb added to command-line options.\n" + "\t Use the -dograb option to enforce grabbing."); + } +#endif + m_canGrab = (!underDebugger && noGrabArg) || (underDebugger && doGrabArg); + + static bool canNotGrabEnv = qEnvironmentVariableIsSet("QT_XCB_NO_GRAB_SERVER"); + if (canNotGrabEnv) + m_canGrab = false; + + m_connections << new QXcbConnection(m_nativeInterface.data(), m_canGrab, displayName); for (int i = 0; i < parameters.size() - 1; i += 2) { #ifdef Q_XCB_DEBUG diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index ffb068ecb3..db6ad541ea 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -117,6 +117,7 @@ private: mutable QByteArray m_wmClass; const char *m_instanceName; + bool m_canGrab; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5d3206b097..85af8ee1d2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2170,6 +2170,9 @@ void QXcbWindow::updateSyncRequestCounter() bool QXcbWindow::setKeyboardGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; @@ -2185,6 +2188,9 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab) bool QXcbWindow::setMouseGrabEnabled(bool grab) { + if (grab && !connection()->canGrab()) + return false; + if (!grab) { xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME); return true; From e3240214e4a200acb7068c6ee8706344929d2446 Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 11 Nov 2014 11:44:51 +0100 Subject: [PATCH 197/323] tst_qitemdelegate: make the test more robust Change-Id: Ieb05d7a05d5d8f6f652a0351deba7208d0770dd6 Reviewed-by: Friedemann Kleint --- .../widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp index 766065acda..f000907e0e 100644 --- a/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp +++ b/tests/auto/widgets/itemviews/qitemdelegate/tst_qitemdelegate.cpp @@ -782,10 +782,8 @@ void tst_QItemDelegate::dateTimeEditor() widget.setFocus(); widget.editItem(item2); - QTestEventLoop::instance().enterLoop(1); - + QTRY_VERIFY(widget.viewport()->findChild()); QDateEdit *dateEditor = widget.viewport()->findChild(); - QVERIFY(dateEditor); QCOMPARE(dateEditor->date(), date); dateEditor->setDate(date.addDays(60)); From 9b7bdd455fefc2df78eb540e9f570877aa8cd827 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 7 Nov 2014 14:42:06 +0100 Subject: [PATCH 198/323] rcc: Replace all occurrences of the marker in two-pass mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The marker can occur legitimately twice e.g. on iOS with universal binaries. Change-Id: Ie334bcd104d45140ff969f44230e6de2212e8e25 Reviewed-by: Tor Arne Vestbø Reviewed-by: Fawzi Mohamed --- src/tools/rcc/rcc.cpp | 52 +++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 9d8a7b7051..d7f8e47213 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -730,33 +730,37 @@ bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIO { m_errorDevice = &errorDevice; - const char pattern[] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' }; if (m_format == Pass2) { - char c; - for (int i = 0; i < 8; ) { - if (!tempDevice.getChar(&c)) { - m_errorDevice->write("No data signature found\n"); - return false; - } - if (c == pattern[i]) { - ++i; - } else { - for (int k = 0; k < i; ++k) - outDevice.putChar(pattern[k]); - outDevice.putChar(c); - i = 0; + const char pattern[] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' }; + bool foundSignature = false; + + while (true) { + char c; + for (int i = 0; i < 8; ) { + if (!tempDevice.getChar(&c)) { + if (foundSignature) + return true; + m_errorDevice->write("No data signature found\n"); + return false; + } + if (c == pattern[i]) { + ++i; + } else { + for (int k = 0; k < i; ++k) + outDevice.putChar(pattern[k]); + outDevice.putChar(c); + i = 0; + } } + + m_outDevice = &outDevice; + quint64 start = outDevice.pos(); + writeDataBlobs(); + quint64 len = outDevice.pos() - start; + + tempDevice.seek(tempDevice.pos() + len - 8); + foundSignature = true; } - - m_outDevice = &outDevice; - quint64 start = outDevice.pos(); - writeDataBlobs(); - quint64 len = outDevice.pos() - start; - - tempDevice.seek(tempDevice.pos() + len - 8); - outDevice.write(tempDevice.readAll()); - - return true; } //write out From 18e4fd1dd1babe3b4178d8815594f4d3af87df19 Mon Sep 17 00:00:00 2001 From: Julien Brianceau Date: Fri, 7 Nov 2014 09:55:24 +0100 Subject: [PATCH 199/323] Compile fix for QT_NO_TEXTHTMLPARSER in QtWidgets Change-Id: If67c851cf45ca53ac4af56d4dc36db24ea896ba1 Reviewed-by: Laszlo Agocs --- src/widgets/accessible/simplewidgets.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/widgets/accessible/simplewidgets.cpp b/src/widgets/accessible/simplewidgets.cpp index ade5cfe3dc..41692d11bd 100644 --- a/src/widgets/accessible/simplewidgets.cpp +++ b/src/widgets/accessible/simplewidgets.cpp @@ -414,12 +414,14 @@ QString QAccessibleDisplay::text(QAccessible::Text t) const if (qobject_cast(object())) { QLabel *label = qobject_cast(object()); str = label->text(); +#ifndef QT_NO_TEXTHTMLPARSER if (label->textFormat() == Qt::RichText || (label->textFormat() == Qt::AutoText && Qt::mightBeRichText(str))) { QTextDocument doc; doc.setHtml(str); str = doc.toPlainText(); } +#endif if (label->buddy()) str = qt_accStripAmp(str); #ifndef QT_NO_LCDNUMBER From 8ce93376cd6aa1fac0eeacbd804bc211b0814c91 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Tue, 28 Oct 2014 16:56:05 +0100 Subject: [PATCH 200/323] OS X and iOS: Search for openssl libs in .app/Contents/Frameworks This allows apps to ship their own openssl libraries inside the application bundle. The change consists of two parts: First, adding /Contents/Frameworks to the alternative search paths. Second, disabling the preemtive check for libssl.dylib, libcrypto.dylib in the system paths: The system's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will still be picked up as a fallback in the alternative search paths, but only after .app/Contents/Frameworks have been inspected. [ChangeLog][QtNetwork][QSsl] On OS X and iOS, openssl dylib's are picked up from the 'Frameworks' directory of the app bundle. Change-Id: I982930f4a6cf5e0114c04ecbc87f27e54ba8bb88 Reviewed-by: Jake Petroules --- .../ssl/qsslsocket_openssl_symbols.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index f4562cdb21..71b8237e03 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -63,6 +63,9 @@ #if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #include #endif +#ifdef Q_OS_DARWIN +#include "private/qcore_mac_p.h" +#endif #include @@ -452,6 +455,15 @@ static QStringList libraryPathList() # ifdef Q_OS_DARWIN paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH")) .split(QLatin1Char(':'), QString::SkipEmptyParts); + + // search in .app/Contents/Frameworks + UInt32 packageType; + CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, NULL); + if (packageType == FOUR_CHAR_CODE('APPL')) { + QUrl bundleUrl = QUrl::fromCFURL(QCFType(CFBundleCopyBundleURL(CFBundleGetMainBundle()))); + QUrl frameworksUrl = QUrl::fromCFURL(QCFType(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle()))); + paths << bundleUrl.resolved(frameworksUrl).path(); + } # else paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH")) .split(QLatin1Char(':'), QString::SkipEmptyParts); @@ -601,7 +613,13 @@ static QPair loadOpenSsl() } #endif +#ifndef Q_OS_DARWIN // second attempt: find the development files libssl.so and libcrypto.so + // + // disabled on OS X/iOS: + // OS X's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third + // attempt, _after_ /Contents/Frameworks has been searched. + // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place. libssl->setFileNameAndVersion(QLatin1String("ssl"), -1); libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1); if (libcrypto->load() && libssl->load()) { @@ -611,6 +629,7 @@ static QPair loadOpenSsl() libssl->unload(); libcrypto->unload(); } +#endif // third attempt: loop on the most common library paths and find libssl QStringList sslList = findAllLibSsl(); From 320c1e0540b31eae227221dc34dfab9a8bd20afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Tue, 4 Nov 2014 15:43:55 +0100 Subject: [PATCH 201/323] Document unified title and toolbar limitations. Change-Id: Ib64a4586c186001730895e6771b01bb213d53b9f Reviewed-by: Timur Pocheptsov Reviewed-by: Shawn Rutledge --- src/widgets/widgets/qmainwindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp index f9376a78d5..ddecea81bf 100644 --- a/src/widgets/widgets/qmainwindow.cpp +++ b/src/widgets/widgets/qmainwindow.cpp @@ -1500,6 +1500,13 @@ bool QMainWindow::event(QEvent *event) /*! \property QMainWindow::unifiedTitleAndToolBarOnMac \brief whether the window uses the unified title and toolbar look on Mac OS X + + Note that the Qt 5 implementation has several limitations compared to Qt 4: + \list + \li Use in windows with OpenGL content is not supported. This includes QGLWidget and QOpenGLWidget. + \li Using dockable or movable toolbars may result in painting errors and is not recommended + \endlist + \since 5.2 */ void QMainWindow::setUnifiedTitleAndToolBarOnMac(bool set) From 501c510cc3cb6215aed27af7599395480a049667 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 11 Nov 2014 13:48:27 +0100 Subject: [PATCH 202/323] Do not apply subpixel gamma-correction on XCB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To match rendering of subpixel antialiased text in Qt 4.8 and other toolkits on X11, we should not apply gamma-correction. This also makes the rendering of subpixel antialiased text closer to normal antialiased text. Task-number: QTBUG-41590 Change-Id: I45ad3448334951353657b878d002eea429858f2d Reviewed-by: Samuel Rødal Reviewed-by: Sérgio Martins Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/xcb/qxcbintegration.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index cace087613..3818494d99 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -427,12 +427,14 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const case QPlatformIntegration::StartDragTime: case QPlatformIntegration::KeyboardAutoRepeatRate: case QPlatformIntegration::PasswordMaskDelay: - case QPlatformIntegration::FontSmoothingGamma: case QPlatformIntegration::StartDragVelocity: case QPlatformIntegration::UseRtlExtensions: case QPlatformIntegration::PasswordMaskCharacter: // TODO using various xcb, gnome or KDE settings break; // Not implemented, use defaults + case QPlatformIntegration::FontSmoothingGamma: + // Match Qt 4.8 text rendering, and rendering of other X11 toolkits. + return qreal(1.0); case QPlatformIntegration::StartDragDistance: { // The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but // on a high-resolution screen it makes sense to increase it. From 3f7e3b1c2450a0c241cbd3a5331484bfeea219f1 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Tue, 11 Nov 2014 15:30:16 +0100 Subject: [PATCH 203/323] QGraphicsItem: document that setOpacity(0) almost makes the item invisible This particular "feature" leaked into QtQuick1 back in the day. Still it was never documented in QGraphicsView. Task-number: QTBUG-18267 Change-Id: Ib5fb446015176f6e9b4095f6ec9030258cbd1ad4 Reviewed-by: Andreas Aardal Hanssen --- src/widgets/graphicsview/qgraphicsitem.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 300e2f492b..8df2263325 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -2447,7 +2447,12 @@ void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly, Items are visible by default; it is unnecessary to call setVisible() on a new item. - \sa isVisible(), show(), hide() + \note An item with opacity set to 0 will still be considered visible, + although it will be treated like an invisible item: mouse events will pass + through it, it will not be included in the items returned by + QGraphicsView::items(), and so on. However, the item will retain the focus. + + \sa isVisible(), show(), hide(), setOpacity() */ void QGraphicsItem::setVisible(bool visible) { @@ -2715,7 +2720,11 @@ qreal QGraphicsItem::effectiveOpacity() const with the parent: ItemIgnoresParentOpacity and ItemDoesntPropagateOpacityToChildren. - \sa opacity(), effectiveOpacity() + \note Setting the opacity of an item to 0 will not make the item invisible + (according to isVisible()), but the item will be treated like an invisible + one. See the documentation of setVisible() for more information. + + \sa opacity(), effectiveOpacity(), setVisible() */ void QGraphicsItem::setOpacity(qreal opacity) { From 459a32e39b45de7f857c090427f29749bf801c49 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Sat, 8 Nov 2014 19:30:56 +0100 Subject: [PATCH 204/323] mkspec macx-ios-clang: ensure SDK version is valid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure the sdk is of recent enough version since: 1. we build Qt with the latest sdk version, so the app needs to do the same to avoid compatibility problems e.g when linking. 2. using a launch screen to support iphone6 depends on sdk 8 3. Apple requires apps that are pushed to appstore to use the latest version of the sdk. Ideally we should store the sdk version used to build Qt, and require that apps use the same version or newer. But this patch will do until that is in place. Change-Id: I18b06d09c1eda15122975b7169ca7a3372df6054 Reviewed-by: Oswald Buddenhagen Reviewed-by: Tor Arne Vestbø --- mkspecs/features/mac/sdk.prf | 4 ++++ mkspecs/macx-ios-clang/features/sdk.prf | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 mkspecs/macx-ios-clang/features/sdk.prf diff --git a/mkspecs/features/mac/sdk.prf b/mkspecs/features/mac/sdk.prf index 36bff00496..97be211595 100644 --- a/mkspecs/features/mac/sdk.prf +++ b/mkspecs/features/mac/sdk.prf @@ -9,8 +9,12 @@ isEmpty(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path) { QMAKE_MAC_SDK_PATH = $$system("/usr/bin/xcodebuild -sdk $$QMAKE_MAC_SDK -version Path 2>/dev/null") isEmpty(QMAKE_MAC_SDK_PATH): error("Could not resolve SDK path for \'$$QMAKE_MAC_SDK\'") cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path, set stash, QMAKE_MAC_SDK_PATH) + QMAKE_MAC_SDK_VERSION = $$system("/usr/bin/xcodebuild -sdk $$QMAKE_MAC_SDK -version SDKVersion 2>/dev/null") + isEmpty(QMAKE_MAC_SDK_VERSION): error("Could not resolve SDK version for \'$$QMAKE_MAC_SDK\'") + cache(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.version, set stash, QMAKE_MAC_SDK_VERSION) } else { QMAKE_MAC_SDK_PATH = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path) + QMAKE_MAC_SDK_VERSION = $$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.version) } !equals(MAKEFILE_GENERATOR, XCODE) { diff --git a/mkspecs/macx-ios-clang/features/sdk.prf b/mkspecs/macx-ios-clang/features/sdk.prf new file mode 100644 index 0000000000..607a71bb26 --- /dev/null +++ b/mkspecs/macx-ios-clang/features/sdk.prf @@ -0,0 +1,4 @@ +load(sdk) + +lessThan(QMAKE_MAC_SDK_VERSION, "8.0"): \ + error("Current $$QMAKE_MAC_SDK SDK version ($$QMAKE_MAC_SDK_VERSION) is too old. Please upgrade Xcode.") From a4428d480b96d51f9979d45044f26c99fa82f465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 31 Oct 2014 16:56:25 +0100 Subject: [PATCH 205/323] Fix for current_fbo getting out of sync in QtOpenGL When using QGLWidget in combination with QOpenGLFramebufferObject from QtGui, instead of QGLFramebufferObject from QtOpenGL, the current_fbo variable doesn't get updated when framebuffer object bindings change. To ensure that the QGLWidget correctly releases the currently bound framebuffer object when using a QPainter, we keep track of whether QOpenGLFramebufferObject has modified the current FBO binding, and if that's the case we need to read the OpenGL state directly instead of relying on a cached value. Change-Id: If7e0bd936e202cad07365b5ce641ee01d2251930 Reviewed-by: Laszlo Agocs --- src/gui/kernel/qopenglcontext_p.h | 3 + src/gui/opengl/qopenglframebufferobject.cpp | 16 ++++- .../qtextureglyphcache_gl.cpp | 2 + src/opengl/qgl.cpp | 29 +++++++++ src/opengl/qgl_p.h | 2 + src/opengl/qglframebufferobject.cpp | 17 +++-- src/opengl/qglpaintdevice.cpp | 13 +++- src/opengl/qglpixelbuffer.cpp | 2 + tests/auto/opengl/qgl/tst_qgl.cpp | 63 +++++++++++++++++++ 9 files changed, 138 insertions(+), 9 deletions(-) diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index d5a3126176..975553e7cd 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -203,6 +203,7 @@ public: , workaround_brokenTexSubImage(false) , workaround_missingPrecisionQualifiers(false) , active_engine(0) + , qgl_current_fbo_invalid(false) { requestedFormat = QSurfaceFormat::defaultFormat(); } @@ -237,6 +238,8 @@ public: QPaintEngineEx *active_engine; + bool qgl_current_fbo_invalid; + QVariant nativeHandle; static QOpenGLContext *setCurrentContext(QOpenGLContext *context); diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index b185e332e6..83cfaf8f93 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -469,6 +469,8 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi funcs.glGenFramebuffers(1, &fbo); funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); + QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; + GLuint color_buffer = 0; QT_CHECK_GLERROR(); @@ -997,7 +999,11 @@ bool QOpenGLFramebufferObject::bind() if (current->shareGroup() != d->fbo_guard->group()) qWarning("QOpenGLFramebufferObject::bind() called from incompatible context"); #endif + d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); + + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; + if (d->texture_guard || d->format.samples() != 0) d->valid = d->checkFramebufferStatus(current); else @@ -1029,9 +1035,12 @@ bool QOpenGLFramebufferObject::release() qWarning("QOpenGLFramebufferObject::release() called from incompatible context"); #endif - if (current) + if (current) { d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->defaultFramebufferObject()); + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; + } + return true; } @@ -1272,8 +1281,10 @@ bool QOpenGLFramebufferObject::bindDefault() { QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); - if (ctx) + if (ctx) { ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); + QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; + } #ifdef QT_DEBUG else qWarning("QOpenGLFramebufferObject::bindDefault() called without current context."); @@ -1342,6 +1353,7 @@ void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachmen qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context"); #endif d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); + QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; d->initAttachments(current, attachment); } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 211fad267f..8cd26f1ea4 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -167,6 +167,8 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) // ### the QTextureGlyphCache API needs to be reworked to allow // ### resizeTextureData to fail + ctx->d_ptr->refreshCurrentFbo(); + funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo); GLuint tmp_texture; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 1e49d95087..35f08e0092 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -510,6 +510,35 @@ void QGLContextPrivate::setupSharing() { } } +void QGLContextPrivate::refreshCurrentFbo() +{ + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + // if QOpenGLFramebufferObjects have been used in the mean-time, we've lost our cached value + if (guiGlContextPrivate && guiGlContextPrivate->qgl_current_fbo_invalid) { + GLint current; + QOpenGLFunctions *funcs = qgl_functions(); + funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, ¤t); + + current_fbo = current; + + guiGlContextPrivate->qgl_current_fbo_invalid = false; + } +} + +void QGLContextPrivate::setCurrentFbo(GLuint fbo) +{ + current_fbo = fbo; + + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + if (guiGlContextPrivate) + guiGlContextPrivate->qgl_current_fbo_invalid = false; +} + + /*! \fn bool QGLFormat::doubleBuffer() const diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index c4151a3d34..4cf656fd86 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -238,6 +238,8 @@ public: bool ownContext; void setupSharing(); + void refreshCurrentFbo(); + void setCurrentFbo(GLuint fbo); QGLFormat glFormat; QGLFormat reqFormat; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 4ef50e9334..49b28c36b9 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -472,6 +472,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) return; + ctx->d_ptr->refreshCurrentFbo(); + size = sz; target = texture_target; // texture dimensions @@ -1027,7 +1029,7 @@ bool QGLFramebufferObject::bind() d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); d->valid = d->checkFramebufferStatus(); if (d->valid && current) - current->d_ptr->current_fbo = d->fbo(); + current->d_ptr->setCurrentFbo(d->fbo()); return d->valid; } @@ -1060,7 +1062,7 @@ bool QGLFramebufferObject::release() #endif if (current) { - current->d_ptr->current_fbo = current->d_ptr->default_fbo; + current->d_ptr->setCurrentFbo(current->d_ptr->default_fbo); d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_ptr->default_fbo); } @@ -1173,7 +1175,7 @@ bool QGLFramebufferObject::bindDefault() if (!functions.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) return false; - ctx->d_ptr->current_fbo = ctx->d_ptr->default_fbo; + ctx->d_ptr->setCurrentFbo(ctx->d_ptr->default_fbo); functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->default_fbo); #ifdef QT_DEBUG } else { @@ -1320,7 +1322,12 @@ bool QGLFramebufferObject::isBound() const { Q_D(const QGLFramebufferObject); const QGLContext *current = QGLContext::currentContext(); - return current ? current->d_ptr->current_fbo == d->fbo() : false; + if (current) { + current->d_ptr->refreshCurrentFbo(); + return current->d_ptr->current_fbo == d->fbo(); + } + + return false; } /*! @@ -1400,6 +1407,8 @@ void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const Q const int ty0 = th - (targetRect.top() + targetRect.height()); const int ty1 = th - targetRect.top(); + ctx->d_ptr->refreshCurrentFbo(); + functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0); functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0); diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 40cc7bb71d..c07d0a761b 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -74,6 +74,8 @@ void QGLPaintDevice::beginPaint() QGLContext *ctx = context(); ctx->makeCurrent(); + ctx->d_func()->refreshCurrentFbo(); + // Record the currently bound FBO so we can restore it again // in endPaint() and bind this device's FBO // @@ -85,7 +87,7 @@ void QGLPaintDevice::beginPaint() m_previousFBO = ctx->d_func()->current_fbo; if (m_previousFBO != m_thisFBO) { - ctx->d_ptr->current_fbo = m_thisFBO; + ctx->d_func()->setCurrentFbo(m_thisFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); } @@ -102,8 +104,10 @@ void QGLPaintDevice::ensureActiveTarget() if (ctx != QGLContext::currentContext()) ctx->makeCurrent(); + ctx->d_func()->refreshCurrentFbo(); + if (ctx->d_ptr->current_fbo != m_thisFBO) { - ctx->d_ptr->current_fbo = m_thisFBO; + ctx->d_func()->setCurrentFbo(m_thisFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); } @@ -114,8 +118,11 @@ void QGLPaintDevice::endPaint() { // Make sure the FBO bound at beginPaint is re-bound again here: QGLContext *ctx = context(); + + ctx->d_func()->refreshCurrentFbo(); + if (m_previousFBO != ctx->d_func()->current_fbo) { - ctx->d_ptr->current_fbo = m_previousFBO; + ctx->d_func()->setCurrentFbo(m_previousFBO); ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO); } diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 56bfaebe4f..63b624aea2 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -344,6 +344,8 @@ void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const QOpenGLExtensions extensions(ctx->contextHandle()); + ctx->d_ptr->refreshCurrentFbo(); + if (d->blit_fbo) { QOpenGLFramebufferObject::blitFramebuffer(d->blit_fbo, d->fbo); extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, d->blit_fbo->handle()); diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp index 0ba464a82c..d8ad3e1470 100644 --- a/tests/auto/opengl/qgl/tst_qgl.cpp +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -42,6 +42,8 @@ #include #include #include +#include +#include #include #include @@ -78,6 +80,7 @@ private slots: void glWidgetRendering(); void glFBOSimpleRendering(); void glFBORendering(); + void currentFboSync(); void multipleFBOInterleavedRendering(); void glFBOUseInGLWidget(); void glPBufferRendering(); @@ -1138,6 +1141,66 @@ void tst_QGL::glFBORendering() qt_opengl_check_test_pattern(fb); } +class QOpenGLFramebufferObjectPaintDevice : public QOpenGLPaintDevice +{ +public: + QOpenGLFramebufferObjectPaintDevice(int width, int height) + : QOpenGLPaintDevice(width, height) + , m_fbo(width, height, QOpenGLFramebufferObject::CombinedDepthStencil) + { + } + + void ensureActiveTarget() + { + m_fbo.bind(); + } + + QImage toImage() const + { + return m_fbo.toImage(); + } + +private: + QOpenGLFramebufferObject m_fbo; +}; + +void tst_QGL::currentFboSync() +{ + if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) + QSKIP("QGLFramebufferObject not supported on this platform"); + +#if defined(Q_OS_QNX) + QSKIP("Reading the QGLFramebufferObject is unsupported on this platform"); +#endif + + QGLWidget glw; + glw.makeCurrent(); + + { + QGLFramebufferObject fbo1(256, 256, QGLFramebufferObject::CombinedDepthStencil); + + QOpenGLFramebufferObjectPaintDevice fbo2(256, 256); + + QImage sourceImage(256, 256, QImage::Format_ARGB32_Premultiplied); + QPainter sourcePainter(&sourceImage); + qt_opengl_draw_test_pattern(&sourcePainter, 256, 256); + + QPainter fbo1Painter(&fbo1); + + QPainter fbo2Painter(&fbo2); + fbo2Painter.drawImage(0, 0, sourceImage); + fbo2Painter.end(); + + QImage fbo2Image = fbo2.toImage(); + + fbo1Painter.drawImage(0, 0, sourceImage); + fbo1Painter.end(); + + QGLFramebufferObject::bindDefault(); + + QCOMPARE(fbo1.toImage(), fbo2Image); + } +} // Tests multiple QPainters active on different FBOs at the same time, with // interleaving painting. Performance-wise, this is sub-optimal, but it still From f79d96b486c1dd50876001b9c3f65d103e07a18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 4 Nov 2014 20:24:38 +0100 Subject: [PATCH 206/323] Fixed QtGui's GL paint engine getting out of sync when using QtOpenGL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to reset the active_engine belonging to QOpenGLContext whenever we make the QtOpenGL paint engine active, to give the OpenGL paint engine in QtGui a chance to sync its state if we've used the QtOpenGL paint engine inbetween. Change-Id: I445ce2f99bfbacf55650c881c4fdf07f2ff85069 Reviewed-by: Jørgen Lind --- .../qpaintengineex_opengl2.cpp | 21 ++++++++++++++- .../qpaintengineex_opengl2_p.h | 1 + tests/auto/opengl/qgl/tst_qgl.cpp | 27 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 43df311636..1fa5723d85 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -612,6 +612,21 @@ void QGL2PaintEngineExPrivate::resetGLState() #endif } +bool QGL2PaintEngineExPrivate::resetOpenGLContextActiveEngine() +{ + QOpenGLContext *guiGlContext = ctx->contextHandle(); + QOpenGLContextPrivate *guiGlContextPrivate = + guiGlContext ? QOpenGLContextPrivate::get(guiGlContext) : 0; + + if (guiGlContextPrivate && guiGlContextPrivate->active_engine) { + ctx->d_func()->refreshCurrentFbo(); + guiGlContextPrivate->active_engine = 0; + return true; + } + + return false; +} + void QGL2PaintEngineEx::endNativePainting() { Q_D(QGL2PaintEngineEx); @@ -2015,6 +2030,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->ctx = d->device->context(); d->ctx->d_ptr->active_engine = this; + d->resetOpenGLContextActiveEngine(); + const QSize sz = d->device->size(); d->width = sz.width(); d->height = sz.height(); @@ -2080,6 +2097,8 @@ bool QGL2PaintEngineEx::end() ctx->d_ptr->active_engine = 0; + d->resetOpenGLContextActiveEngine(); + d->resetGLState(); delete d->shaderManager; @@ -2105,7 +2124,7 @@ void QGL2PaintEngineEx::ensureActive() Q_D(QGL2PaintEngineEx); QGLContext *ctx = d->ctx; - if (isActive() && ctx->d_ptr->active_engine != this) { + if (isActive() && (ctx->d_ptr->active_engine != this || d->resetOpenGLContextActiveEngine())) { ctx->d_ptr->active_engine = this; d->needsSync = true; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 528bfdeeb9..ac1d63df17 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -191,6 +191,7 @@ public: void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = GLuint(-1)); void resetGLState(); + bool resetOpenGLContextActiveEngine(); // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, // however writeClip can also be thought of as en entry point as it does similar things. diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp index d8ad3e1470..56198ceb65 100644 --- a/tests/auto/opengl/qgl/tst_qgl.cpp +++ b/tests/auto/opengl/qgl/tst_qgl.cpp @@ -1200,6 +1200,33 @@ void tst_QGL::currentFboSync() QCOMPARE(fbo1.toImage(), fbo2Image); } + + { + QGLFramebufferObject fbo1(512, 512, QGLFramebufferObject::CombinedDepthStencil); + + QOpenGLFramebufferObjectPaintDevice fbo2(256, 256); + + QImage sourceImage(256, 256, QImage::Format_ARGB32_Premultiplied); + QPainter sourcePainter(&sourceImage); + qt_opengl_draw_test_pattern(&sourcePainter, 256, 256); + + QPainter fbo2Painter(&fbo2); + fbo2Painter.drawImage(0, 0, sourceImage); + QImage fbo2Image1 = fbo2.toImage(); + fbo2Painter.fillRect(0, 0, 256, 256, Qt::white); + + QPainter fbo1Painter(&fbo1); + fbo1Painter.drawImage(0, 0, sourceImage); + fbo1Painter.end(); + + // check that the OpenGL paint engine now knows it needs to sync + fbo2Painter.drawImage(0, 0, sourceImage); + QImage fbo2Image2 = fbo2.toImage(); + + fbo2Painter.end(); + + QCOMPARE(fbo2Image1, fbo2Image2); + } } // Tests multiple QPainters active on different FBOs at the same time, with From 1ad78f5f29ef00abae4f718265fa4bc0c35b60f9 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Tue, 21 Oct 2014 10:22:45 +0200 Subject: [PATCH 207/323] qdoc: Prepare QDoc for the new style on qt.io The new template and CSS have some requirements that need changes in the generated .html: - Generate a new div 'sidebar' and place the TOC (if one exists) inside it, allowing the template to extend the sidebar contents dynamically. Do this for all pages except index.html. - Change the DOCTYPE declaration to be html5-compliant - Replace tags with to be html5-compliant - Add a new config variable HTML.prologue - this allows the template to insert custom html into beginning of the page, before the page title but after any navigation or table-of-contents items. - Wrap tables inside

elements. This allows for better-working CSS design for small-screen devices. - Write out extra parameters first when outputting function synopsis to have better styling. - Inject zero-width-space characters into function names to allow the browser break up long function signatures in a nice manner. - Edit the CSS for the offline style to adapt to above changes. Task-number: QTBUG-42086 Change-Id: I3075cdc11bcb07a66150388519263fd721c8002b Reviewed-by: Martin Smith --- doc/global/template/style/offline.css | 19 ++++- src/tools/qdoc/cppcodemarker.cpp | 12 +-- src/tools/qdoc/htmlgenerator.cpp | 109 +++++++++++++++----------- src/tools/qdoc/htmlgenerator.h | 3 + 4 files changed, 90 insertions(+), 53 deletions(-) diff --git a/doc/global/template/style/offline.css b/doc/global/template/style/offline.css index 126df9d806..dc0a6d1ec9 100644 --- a/doc/global/template/style/offline.css +++ b/doc/global/template/style/offline.css @@ -359,7 +359,9 @@ h3.fn, span.fn { margin: 0px; margin-top: 45px; } - +h3.fn code { + float: right; +} h3.fn:target { background-color: #F6F6D6; } @@ -705,8 +707,21 @@ Landing page float: left; } -.icons1of3 h2 { +.icons1of3 h2, .doc-column h2 { font-size: 15px; margin: 0px; padding: 0px; } + +div.multi-column { + position: relative; +} + +div.multi-column div { + display: -moz-inline-box; + display: inline-block; + vertical-align: top; + margin-top: 1em; + margin-right: 4em; + width: 24em; +} diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp index 48218da513..92b6ccca6a 100644 --- a/src/tools/qdoc/cppcodemarker.cpp +++ b/src/tools/qdoc/cppcodemarker.cpp @@ -136,7 +136,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, if ((style == Detailed) && !node->parent()->name().isEmpty() && (node->type() != Node::Property) && !node->isQmlNode()) - name.prepend(taggedNode(node->parent()) + "::"); + name.prepend(taggedNode(node->parent()) + "::​"); switch (node->type()) { case Node::Namespace: @@ -212,7 +212,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, bracketed += "slot"; } if (!bracketed.isEmpty()) - extra += " [" + bracketed.join(' ') + QLatin1Char(']'); + extra += QLatin1Char('[') + bracketed.join(' ') + QStringLiteral("] "); } break; case Node::Enum: @@ -283,13 +283,13 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, if (style == Summary) { if (node->status() == Node::Preliminary) { - extra += " (preliminary)"; + extra += "(preliminary) "; } else if (node->status() == Node::Deprecated) { - extra += " (deprecated)"; + extra += "(deprecated) "; } else if (node->status() == Node::Obsolete) { - extra += " (obsolete)"; + extra += "(obsolete) "; } } @@ -297,7 +297,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, extra.prepend("<@extra>"); extra.append(""); } - return synopsis + extra; + return extra + synopsis; } /*! diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index 5b8ccd9902..bd8d45ab53 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -121,7 +121,7 @@ void HtmlGenerator::initializeGenerator(const Config &config) { ATOM_FORMATTING_PARAMETER, "", "" }, { ATOM_FORMATTING_SUBSCRIPT, "", "" }, { ATOM_FORMATTING_SUPERSCRIPT, "", "" }, - { ATOM_FORMATTING_TELETYPE, "", "" }, + { ATOM_FORMATTING_TELETYPE, "", "" }, // tag is not supported in HTML5 { ATOM_FORMATTING_UICONTROL, "", "" }, { ATOM_FORMATTING_UNDERLINE, "", "" }, { 0, 0, 0 } @@ -149,6 +149,10 @@ void HtmlGenerator::initializeGenerator(const Config &config) postPostHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTPOSTHEADER); + prologue = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_PROLOGUE); + footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); @@ -845,7 +849,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "
\n"; } else if (atom->string() == ATOM_LIST_VALUE) { - out() << ""; + out() << "
"; threeColumnEnumValueTable_ = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable_) { if (++numTableRows_ % 2 == 1) @@ -897,7 +901,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark // ### Trenton QString t= protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),relative))); - out() << "
" << t << ""; + out() << "
" << t << ""; if (relative->type() == Node::Enum) { out() << ""; @@ -907,7 +911,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark if (itemValue.isEmpty()) out() << '?'; else - out() << "" << protectEnc(itemValue) << ""; + out() << "" << protectEnc(itemValue) << ""; } skipAhead = 1; } @@ -952,7 +956,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "\n"; } else if (atom->string() == ATOM_LIST_VALUE) { - out() << "
\n"; + out() << "
\n"; } else { out() << "\n"; @@ -1040,7 +1044,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark else if (p2.contains("%")) width = p2; } - out() << "
\n "; @@ -1048,7 +1052,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark } break; case Atom::TableRight: - out() << "
\n"; + out() << "\n"; break; case Atom::TableHeaderLeft: out() << ""; @@ -1456,8 +1460,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker) Generate the TOC for the new doc format. Don't generate a TOC for the home page. */ - if ((dn->name() != QString("index.html")) && - (dn->name() != QString("qtexamplesandtutorials.html"))) + if ((dn->name() != QStringLiteral("index.html"))) generateTableOfContents(dn,marker,0); generateTitle(fullTitle, @@ -1707,8 +1710,8 @@ void HtmlGenerator::generateHeader(const QString& title, #else out() << QString("\n"); #endif - out() << "\n"; - out() << QString("\n").arg(naturalLanguage); + out() << "\n"; + out() << QString("\n").arg(naturalLanguage); out() << "\n"; out() << " \n"; if (node && !node->doc().location().isEmpty()) @@ -1775,7 +1778,8 @@ void HtmlGenerator::generateHeader(const QString& title, out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); generateNavigationBar(title,node,marker); - out() << "
  • \n" << buildversion << "
  • \n"; + if (!buildversion.isEmpty()) + out() << "
  • " << buildversion << "
  • \n"; out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); navigationLinks.clear(); @@ -1849,6 +1853,7 @@ void HtmlGenerator::generateTitle(const QString& title, const Node *relative, CodeMarker *marker) { + out() << QString(prologue).replace("\\" + COMMAND_VERSION, qdb_->version()); if (!title.isEmpty()) out() << "

    " << protectEnc(title) << "

    \n"; if (!subTitle.isEmpty()) { @@ -1993,7 +1998,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) if (!requisites.isEmpty()) { //generate the table - out() << "\n"; + out() << "
    \n"; QStringList::ConstIterator i; for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { @@ -2011,7 +2016,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) out() << ""; } } - out() << "
    "; + out() << ""; } } @@ -2112,7 +2117,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker) if (!requisites.isEmpty()) { //generate the table - out() << "\n"; + out() << "
    \n"; QStringList::ConstIterator i; for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) { @@ -2130,7 +2135,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker) out() << ""; } } - out() << "
    "; + out() << ""; } } @@ -2176,12 +2181,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node, QList toc; if (node->doc().hasTableOfContents()) toc = node->doc().tableOfContents(); - if (toc.isEmpty() && !sections && !node->isModule()) - return; - - //turn off table of contents if HTML.tocdepth is set to 0 - if (tocDepth == 0) + if (tocDepth == 0 || (toc.isEmpty() && !sections && !node->isModule())) { + generateSidebar(); return; + } QStringList sectionNumber; int detailsBase = 0; @@ -2190,6 +2193,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node, inContents_ = true; inLink_ = true; + out() << "
    \n"; out() << "
    \n"; out() << "

    Contents

    \n"; sectionNumber.append("1"); @@ -2287,10 +2291,21 @@ void HtmlGenerator::generateTableOfContents(const Node *node, } out() << "\n"; out() << "
    \n"; + out() << "
    "; + out() << "
    \n"; inContents_ = false; inLink_ = false; } +/*! + Outputs a placeholder div where the style can add customized sidebar content. + */ +void HtmlGenerator::generateSidebar() { + out() << "
    "; + out() << "
    "; + out() << "
    \n"; +} + QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker) { @@ -2307,6 +2322,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, beginSubPage(inner, fileName); QString title = "List of All Members for " + inner->name(); generateHeader(title, inner, marker); + generateSidebar(); generateTitle(title, Text(), SmallSubTitle, inner, marker); out() << "

    This is the complete list of members for "; generateFullName(inner, 0); @@ -2338,6 +2354,7 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarke beginSubPage(qml_cn, fileName); QString title = "List of All Members for " + qml_cn->name(); generateHeader(title, qml_cn, marker); + generateSidebar(); generateTitle(title, Text(), SmallSubTitle, qml_cn, marker); out() << "

    This is the complete list of members for "; generateFullName(qml_cn, 0); @@ -2422,6 +2439,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner, beginSubPage(inner, fileName); generateHeader(title, inner, marker); + generateSidebar(); generateTitle(title, Text(), SmallSubTitle, inner, marker); if (status == CodeMarker::Compat) { @@ -2498,6 +2516,7 @@ QString HtmlGenerator::generateQmlMemberFile(QmlClassNode* qcn, beginSubPage(qcn, fileName); generateHeader(title, qcn, marker); + generateSidebar(); generateTitle(title, Text(), SmallSubTitle, qcn, marker); out() << "

    The following members of QML type " @@ -2615,7 +2634,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, } if (allInternal) return; - out() << "\n"; + out() << "
    \n"; int row = 0; NodeList nodes = nm.values(); foreach (const Node* node, nodes) { @@ -2651,7 +2670,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, } out() << "\n"; } - out() << "
    \n"; + out() << "\n"; } /*! @@ -2902,8 +2921,8 @@ void HtmlGenerator::generateQmlItem(const Node *node, if (summary) marked.replace("@name>", "b>"); - marked.replace("<@extra>", ""); - marked.replace("", ""); + marked.replace("<@extra>", ""); + marked.replace("", ""); if (summary) { marked.remove("<@type>"); @@ -3027,11 +3046,11 @@ void HtmlGenerator::generateSection(const NodeList& nl, alignNames = false; } if (alignNames) { - out() << "\n"; + out() << "
    \n"; } else { if (twoColumn) - out() << "
    \n" + out() << "
    \n" << "
    "; out() << "
      \n"; } @@ -3062,11 +3081,11 @@ void HtmlGenerator::generateSection(const NodeList& nl, ++m; } if (alignNames) - out() << "
    \n"; + out() << "\n"; else { out() << "\n"; if (twoColumn) - out() << "\n\n"; + out() << "\n\n"; } } } @@ -3088,11 +3107,11 @@ void HtmlGenerator::generateSectionList(const Section& section, alignNames = false; } if (alignNames) { - out() << "\n"; + out() << "
    \n"; } else { if (twoColumn) - out() << "
    \n" + out() << "
    \n" << "
    "; out() << "
      \n"; } @@ -3128,11 +3147,11 @@ void HtmlGenerator::generateSectionList(const Section& section, ++m; } if (alignNames) - out() << "
    \n"; + out() << "\n"; else { out() << "\n"; if (twoColumn) - out() << "\n\n"; + out() << "\n\n"; } } @@ -3196,8 +3215,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, extraRegExp.setMinimal(true); marked.remove(extraRegExp); } else { - marked.replace("<@extra>", ""); - marked.replace("", ""); + marked.replace("<@extra>", ""); + marked.replace("", ""); } if (style != CodeMarker::Detailed) { @@ -4058,7 +4077,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, const QmlPropertyGroupNode* qpgn = static_cast(node); NodeList::ConstIterator p = qpgn->childNodes().constBegin(); out() << "

    "; - out() << ""; + out() << "
    "; QString heading = qpgn->name() + " group"; out() << ""; @@ -4083,13 +4102,13 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, } ++p; } - out() << "
    "; + out() << "
    "; out() << ""; } else if (node->type() == Node::QmlProperty) { qpn = static_cast(node); out() << "
    "; - out() << ""; + out() << "
    "; out() << ""; out() << ""; - out() << "

    "; out() << ""; @@ -4103,43 +4122,43 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, out() << "default"; generateQmlItem(qpn, relative, marker, false); out() << "

    "; + out() << "
    "; out() << ""; } else if (node->type() == Node::QmlSignal) { const FunctionNode* qsn = static_cast(node); out() << "
    "; - out() << ""; + out() << "
    "; out() << ""; out() << ""; - out() << "

    "; out() << ""; generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false); out() << "

    "; + out() << "
    "; out() << ""; } else if (node->type() == Node::QmlSignalHandler) { const FunctionNode* qshn = static_cast(node); out() << "
    "; - out() << ""; + out() << "
    "; out() << ""; out() << ""; - out() << "

    "; out() << ""; generateSynopsis(qshn,relative,marker,CodeMarker::Detailed,false); out() << "

    "; + out() << "
    "; out() << ""; } else if (node->type() == Node::QmlMethod) { const FunctionNode* qmn = static_cast(node); out() << "
    "; - out() << ""; + out() << "
    "; out() << ""; out() << ""; - out() << "

    "; out() << ""; generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); out() << "

    "; + out() << "
    "; out() << ""; } out() << "
    "; diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h index 616a989361..40360da02e 100644 --- a/src/tools/qdoc/htmlgenerator.h +++ b/src/tools/qdoc/htmlgenerator.h @@ -144,6 +144,7 @@ private: void generateTableOfContents(const Node *node, CodeMarker *marker, QList
    * sections = 0); + void generateSidebar(); QString generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker); QString generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarker* marker); @@ -238,6 +239,7 @@ private: QString endHeader; QString postHeader; QString postPostHeader; + QString prologue; QString footer; QString address; bool pleaseGenerateMacRef; @@ -272,6 +274,7 @@ public: #define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me #define HTMLGENERATOR_POSTHEADER "postheader" #define HTMLGENERATOR_POSTPOSTHEADER "postpostheader" +#define HTMLGENERATOR_PROLOGUE "prologue" #define HTMLGENERATOR_NONAVIGATIONBAR "nonavigationbar" #define HTMLGENERATOR_NOSUBDIRS "nosubdirs" #define HTMLGENERATOR_TOCDEPTH "tocdepth" From 0c2f7388a89a9d8ae24379cdbee11a9f85304d19 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 11 Nov 2014 10:25:14 +0100 Subject: [PATCH 208/323] Windows: Remove font size hack This hack was reintroduced in a4478b28966c5f630ba3d93b97bc91a3cec2fdbe, and hides scaling artifacts in fonts where there is heavy hinting, such as Arial, but introduces new bugs in other fonts, such as Vijaya. The bottom line is that we shouldn't arbitrarily override the pixel size of the font with the character height that we get from GDI. Due to hinting, there will be some artifacts when printing with screen resolution on Windows. The only way to make this look correct is to use high resolution printing, like the documentation says, or perhaps to force design metrics on the text layout. Task-number: QTBUG-40770 Change-Id: Id151eb0ede5f73efb2a401924ce379d4414ca2b1 Reviewed-by: Lars Knoll --- src/gui/painting/qpdf.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 1da0c6b65f..9082f98205 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2524,10 +2524,6 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti) qreal size = ti.fontEngine->fontDef.pixelSize; -#if defined(Q_OS_WIN) - size = (ti.fontEngine->ascent() + ti.fontEngine->descent()).toReal(); -#endif - QVarLengthArray glyphs; QVarLengthArray positions; QTransform m = QTransform::fromTranslate(p.x(), p.y()); From d4fcf2ca40e635cc0f198afe6e17e88ba098835b Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 3 Nov 2014 11:23:05 +0100 Subject: [PATCH 209/323] iOS: let qmake generate default LaunchScreen.xib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit iOS8 will check if the app has a LaunchScreen.xib to determine if it supports iPhone6/6+ (scale factor and resolution). So we follow the same pattern as we do with the launch image for iPhone5, and generate a default LaunchScreen.xib. The xib file in this patch is a copy of a default file generated by a native Xcode project (with quotes escaped), but with the text label set to be $$TARGET. Change-Id: I163ab48b6f4edea4cc1f6840a1f3d8b3cc0326db Reviewed-by: Tor Arne Vestbø --- mkspecs/macx-ios-clang/Info.plist.app | 2 + mkspecs/macx-ios-clang/LaunchScreen.xib | 45 +++++++++++++++++++ .../macx-ios-clang/features/default_post.prf | 8 ++++ 3 files changed, 55 insertions(+) create mode 100644 mkspecs/macx-ios-clang/LaunchScreen.xib diff --git a/mkspecs/macx-ios-clang/Info.plist.app b/mkspecs/macx-ios-clang/Info.plist.app index 2987804e33..623ed496c5 100755 --- a/mkspecs/macx-ios-clang/Info.plist.app +++ b/mkspecs/macx-ios-clang/Info.plist.app @@ -24,6 +24,8 @@ 1.0 LSRequiresIPhoneOS + UILaunchStoryboardName + LaunchScreen UISupportedInterfaceOrientations UIInterfaceOrientationPortrait diff --git a/mkspecs/macx-ios-clang/LaunchScreen.xib b/mkspecs/macx-ios-clang/LaunchScreen.xib new file mode 100644 index 0000000000..d28c06b375 --- /dev/null +++ b/mkspecs/macx-ios-clang/LaunchScreen.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 2001f53ec4..51a87e3eab 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -184,6 +184,14 @@ macx-xcode { QMAKE_SUBSTITUTES += copy_image launch_images.files = $$copy_image.output QMAKE_BUNDLE_DATA += launch_images + + # Set up default LaunchScreen to support iPhone6/6+ + launch_screen = LaunchScreen.xib + copy_launch_screen.input = $$QMAKESPEC/$$launch_screen + copy_launch_screen.output = $$OUT_PWD/$${TARGET}.xcodeproj/$$launch_screen + QMAKE_SUBSTITUTES += copy_launch_screen + launch_screens.files = $$copy_launch_screen.output + QMAKE_BUNDLE_DATA += launch_screens } macx-xcode { From 91e53a7b9cb30e330c86c8bc460159fe14945042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 6 Nov 2014 16:11:01 +0100 Subject: [PATCH 210/323] Xcode: Make sure QMAKE_PRE_LINK dependencies are complete for multi-arch builds With multi-architecture builds and ONLY_ACTIVE_ARCH set to NO, Xcode will build the final target for multiple architectures at the same time, but CURRENT_ARCH will only match one of them, so we failed to set up the right dependencies for our pre-link step, causing the step to happen after linking in some cases. We now build an exhaustive dependency list based on QMAKE_XCODE_ARCHS, so that ONLY_ACTIVE_ARCH=NO can be used for release builds targeted at the App Store. Change-Id: I6702f020a6970807adc624779f6dde09be62beb9 Reviewed-by: Andy Shaw --- qmake/generators/mac/pbuilder_pbx.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 4624496e99..0ff42500de 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1029,6 +1029,21 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if (!project->isEmpty("QMAKE_PRE_LINK")) { QString phase_key = keyFor("QMAKE_PBX_PRELINK_BUILDPHASE"); project->values("QMAKE_PBX_BUILDPHASES").append(phase_key); + + ProStringList inputPaths; + ProStringList outputPaths; + const ProStringList &archs = project->values("QMAKE_XCODE_ARCHS"); + if (!archs.isEmpty()) { + for (int i = 0; i < archs.size(); ++i) { + const ProString &arch = archs.at(i); + inputPaths << "$(OBJECT_FILE_DIR_$(CURRENT_VARIANT))/" + arch + "/"; + outputPaths << "$(LINK_FILE_LIST_$(CURRENT_VARIANT)_" + arch + ")"; + } + } else { + inputPaths << "$(OBJECT_FILE_DIR_$(CURRENT_VARIANT))/$(CURRENT_ARCH)/"; + outputPaths << "$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(CURRENT_ARCH))"; + } + t << "\t\t" << phase_key << " = {\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";\n" << "\t\t\t" << writeSettings("files", ProStringList(), SettingsAsList, 4) << ";\n" @@ -1036,8 +1051,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) // resolved dependenices, so we have to ensure that this phase is run after the // compilation phase, and before the link phase. Making the phase depend on the // object file directory, and "write" to the list of files to link achieves that. - << "\t\t\t" << writeSettings("inputPaths", ProStringList("$(OBJECT_FILE_DIR_$(CURRENT_VARIANT))/$(CURRENT_ARCH)/"), SettingsAsList, 4) << ";\n" - << "\t\t\t" << writeSettings("outputPaths", ProStringList("$(LINK_FILE_LIST_$(CURRENT_VARIANT)_$(CURRENT_ARCH))"), SettingsAsList, 4) << ";\n" + << "\t\t\t" << writeSettings("inputPaths", inputPaths, SettingsAsList, 4) << ";\n" + << "\t\t\t" << writeSettings("outputPaths", outputPaths, SettingsAsList, 4) << ";\n" << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";\n" << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";\n" << "\t\t\t" << writeSettings("name", "Qt Prelink") << ";\n" From 8ea5b2852e36c93195987a588d893cc8e5b185ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 5 Nov 2014 16:37:59 +0100 Subject: [PATCH 211/323] iOS: Remove assert when transferring or clearing first-responder We'd transfer or clear first-responder in a lot more cases than just when transferring to a new Qt window, such as when presenting a new view-controller on top to send an e-mail or take a picture using the camera. Change-Id: I6b2a8a6d9fd99910b96a86cf9847b7ff0128f20a Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/qiostextresponder.mm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index e3c73f5222..6bd1e711d0 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -268,8 +268,11 @@ qImDebug() << "keyboard was closed, clearing focus object"; m_inputContext->clearCurrentFocusObject(); } else { - // We've lost responder status because another window was made active - Q_ASSERT(FirstResponderCandidate::currentCandidate()); + // We've lost responder status because another Qt window was made active, + // another QIOSTextResponder was made first-responder, another UIView was + // made first-responder, or the first-responder was cleared globally. In + // either of these cases we don't have to do anything. + qImDebug() << "lost first responder, but not clearing focus object"; } return YES; From 3e161dcb3dcee13a942bb7f0aca1a1920808acd3 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 12 Nov 2014 12:14:57 +0100 Subject: [PATCH 212/323] iOS: QtFirstResponderEvent needs to release firstResponder to avoid leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without setting firstResponder to 0 upon destruction, the current retain count would never reach zero after the event was used. The result being that QIOSTextResponder was seldom destroyed, which would also affect its inputView etc which would also be kept alive. Change-Id: Ia88e6a9d8764e7e9532487153e5e81a7ad0f9741 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosglobal.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 9f10c3e287..3ecd0ca61f 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -141,6 +141,11 @@ int infoPlistValue(NSString* key, int defaultValue) @end @implementation QtFirstResponderEvent +- (void) dealloc +{ + self.firstResponder = 0; + [super dealloc]; +} @end From 24a94ab833dac46790a58e8375dc226890994716 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 12 Nov 2014 15:45:43 +0100 Subject: [PATCH 213/323] QGraphicsTextItem: document that adjustSize can center/right align text Unlike QTextEdit, there's no implicit width for a QGraphicsTextItem, meaning any rich text that is supposed to be centered or right aligned will not be unless the user explicitly sets the width. There's also another possibility: calling adjustSize() manually. Document that. Task-number: QTBUG-312 Change-Id: I83023269f4c63643e8224887efe2143dd1bb1908 Reviewed-by: Andy Shaw --- src/widgets/graphicsview/qgraphicsitem.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 8df2263325..03f22a270f 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -9791,6 +9791,7 @@ QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const using textWidth(). \note In order to align HTML text in the center, the item's text width must be set. + Otherwise, you can call adjustSize() after setting the item's text. \image graphicsview-textitem.png From 9ddcb7784ad49af3efe1a0213545dc6782468cfb Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 13 Nov 2014 08:47:41 +0100 Subject: [PATCH 214/323] Prevent a crash when buffer() returns 0 If buffer() returns 0 then there is no bufferPixels available which will cause a crash later on when it tries to set that memory. If this function fails then all we can do is return, a warning will have already been outputted from buffer() itself indicating why. Change-Id: I5890b3c34536f7f3d17def0936970c0a694b005a Reviewed-by: Friedemann Kleint --- src/widgets/styles/qwindowsxpstyle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index c18bbb3431..f79431f312 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -963,7 +963,8 @@ void QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa QImage img; if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! ------------------------- - buffer(w, h); // Ensure a buffer of at least (w, h) in size + if (!buffer(w, h)) // Ensure a buffer of at least (w, h) in size + return; HDC dc = bufferHDC(); // Clear the buffer From c508a9ddf274dcc8834387237a728c78e9ecc3b1 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 30 Oct 2014 11:51:21 +0100 Subject: [PATCH 215/323] Fix MinGW compiler warning in qwindowsxpstyle.cpp. qwindowsxpstyle.cpp: In static member function 'static QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State, const QWidget*, XPThemeData*)':styles\qwindowsxpstyle.cpp:2542:45: warning: suggest parentheses around '&&' within '||' [-Wparentheses] Change-Id: I6a4b62057a612fa9234744e892950c959c513d15 Reviewed-by: Kai Koehne --- src/widgets/styles/qwindowsxpstyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index f79431f312..c1f7b599b3 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -2540,7 +2540,7 @@ QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, const const int hSpace = theme->rect.width() - size.width(); const int vSpace = theme->rect.height() - size.height(); - const bool sufficientSpace = horizontal && hSpace > (contentsMargin.left() + contentsMargin.right()) + const bool sufficientSpace = (horizontal && hSpace > (contentsMargin.left() + contentsMargin.right())) || vSpace > contentsMargin.top() + contentsMargin.bottom(); return sufficientSpace ? QRect(theme->rect.topLeft() + QPoint(hSpace, vSpace) / 2, size) : QRect(); } From 63ae74f36533d92c5b38df1eb2a7fcf4c586bf11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Wed, 12 Nov 2014 12:27:39 +0200 Subject: [PATCH 216/323] Mark QSocks5SocketEngine tests blacklisted Task-number: QTBUG-42528 Change-Id: I3ba17b9d0f604215e6be0ec7199b12bf009c8b55 Reviewed-by: Lars Knoll --- tests/auto/network/socket/qsocks5socketengine/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/auto/network/socket/qsocks5socketengine/BLACKLIST diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST new file mode 100644 index 0000000000..1bc24299e8 --- /dev/null +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -0,0 +1,2 @@ +[udpTest] +[passwordAuth] From 034ff4deaf3e4c998f4572705a1c7624c8499c92 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 7 Nov 2014 15:57:25 +0100 Subject: [PATCH 217/323] Add diaglib under manual tests. Add a set of helper functions and classes providing functionality for dumping widget/window hierarchies and logging events. They can be used by including a .pri file for diagnosing bugs and comparing Qt 5 to Qt 4. Change-Id: I0206f8e57b02540cd80a3e9446c894023d442ddc Reviewed-by: Andy Shaw Reviewed-by: Shawn Rutledge --- tests/manual/diaglib/README.txt | 34 +++ tests/manual/diaglib/diaglib.pri | 43 ++++ tests/manual/diaglib/eventfilter.cpp | 113 ++++++++++ tests/manual/diaglib/eventfilter.h | 77 +++++++ tests/manual/diaglib/glinfo.cpp | 112 ++++++++++ tests/manual/diaglib/glinfo.h | 48 ++++ tests/manual/diaglib/nativewindowdump.cpp | 46 ++++ tests/manual/diaglib/nativewindowdump.h | 46 ++++ tests/manual/diaglib/nativewindowdump_win.cpp | 207 ++++++++++++++++++ tests/manual/diaglib/qwidgetdump.cpp | 94 ++++++++ tests/manual/diaglib/qwidgetdump.h | 45 ++++ tests/manual/diaglib/qwindowdump.cpp | 176 +++++++++++++++ tests/manual/diaglib/qwindowdump.h | 63 ++++++ 13 files changed, 1104 insertions(+) create mode 100644 tests/manual/diaglib/README.txt create mode 100644 tests/manual/diaglib/diaglib.pri create mode 100644 tests/manual/diaglib/eventfilter.cpp create mode 100644 tests/manual/diaglib/eventfilter.h create mode 100644 tests/manual/diaglib/glinfo.cpp create mode 100644 tests/manual/diaglib/glinfo.h create mode 100644 tests/manual/diaglib/nativewindowdump.cpp create mode 100644 tests/manual/diaglib/nativewindowdump.h create mode 100644 tests/manual/diaglib/nativewindowdump_win.cpp create mode 100644 tests/manual/diaglib/qwidgetdump.cpp create mode 100644 tests/manual/diaglib/qwidgetdump.h create mode 100644 tests/manual/diaglib/qwindowdump.cpp create mode 100644 tests/manual/diaglib/qwindowdump.h diff --git a/tests/manual/diaglib/README.txt b/tests/manual/diaglib/README.txt new file mode 100644 index 0000000000..13387f5a2a --- /dev/null +++ b/tests/manual/diaglib/README.txt @@ -0,0 +1,34 @@ +This is a collection of functions and classes helpful for diagnosing bugs +in Qt 4 and Qt 5. It can be included in the application's .pro file by +adding: + +include([path to Qt sources]/tests/manual/diaglib/diaglib.pri) + +For Qt 4, the environment variable QTDIR may be used: +include($$(QTDIR)/tests/manual/diaglib/diaglib.pri) + +The .pri file adds the define QT_DIAG_LIB, so, diagnostic +code can be enlosed within #ifdef to work without it as well. + +All functions and classes are in the QtDiag namespace. + +class EventFilter (eventfilter.h): + An event filter that logs Qt events to qDebug() depending on + configured categories (for example mouse, keyboard, etc). + +function glInfo() (glinfo.h): + Returns a string describing the Open GL configuration (obtained + by querying GL_VENDOR and GL_RENDERER). Available only + when the QT qmake variable contains opengl. + +functions dumpNativeWindows(), dumpNativeQtTopLevels(): + These functions du,p out the hierarchy of native Windows. Currently + implemented for Windows only. + +function dumpAllWidgets() (qwidgetdump.h): + Dumps the hierarchy of QWidgets including information about flags, + visibility, geometry, etc. + +function dumpAllWindows() (qwindowdump.h): + Dumps the hierarchy of QWindows including information about flags, + visibility, geometry, etc. diff --git a/tests/manual/diaglib/diaglib.pri b/tests/manual/diaglib/diaglib.pri new file mode 100644 index 0000000000..138660f85e --- /dev/null +++ b/tests/manual/diaglib/diaglib.pri @@ -0,0 +1,43 @@ +INCLUDEPATH += $$PWD +SOURCES += \ + $$PWD/eventfilter.cpp \ + $$PWD/qwindowdump.cpp \ + +HEADERS += \ + $$PWD/eventfilter.h \ + $$PWD/qwindowdump.h \ + $$PWD/nativewindowdump.h + +win32 { + SOURCES += $$PWD/nativewindowdump_win.cpp + LIBS *= -luser32 +} else { + SOURCES += $$PWD/nativewindowdump.cpp +} + +greaterThan(QT_MAJOR_VERSION, 4) { + QT += gui-private core-private + contains(QT, widgets) { + HEADERS += \ + $$PWD/$$PWD/qwidgetdump.h + + SOURCES += \ + $$PWD/qwidgetdump.cpp + } +} else { + HEADERS += \ + $$PWD/$$PWD/qwidgetdump.h + + SOURCES += \ + $$PWD/qwidgetdump.cpp +} + +contains(QT, opengl) { +HEADERS += \ + $$PWD/glinfo.h + +SOURCES += \ + $$PWD/glinfo.cpp +} + +DEFINES += QT_DIAG_LIB diff --git a/tests/manual/diaglib/eventfilter.cpp b/tests/manual/diaglib/eventfilter.cpp new file mode 100644 index 0000000000..f0573975f6 --- /dev/null +++ b/tests/manual/diaglib/eventfilter.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "eventfilter.h" +#include +#include +#include + +namespace QtDiag { + +EventFilter::EventFilter(EventCategories eventCategories, QObject *p) + : QObject(p) +{ + init(eventCategories); +} + +EventFilter::EventFilter(QObject *p) + : QObject(p) +{ + init(EventCategories(0xFFFFFFF)); +} + +void EventFilter::init(EventCategories eventCategories) +{ + if (eventCategories & MouseEvents) { + m_eventTypes << QEvent::MouseButtonPress << QEvent::MouseButtonRelease + << QEvent::MouseButtonDblClick << QEvent::NonClientAreaMouseButtonPress + << QEvent::NonClientAreaMouseButtonRelease + << QEvent::NonClientAreaMouseButtonDblClick + << QEvent::Enter << QEvent::Leave; + } + if (eventCategories & MouseMoveEvents) + m_eventTypes << QEvent::MouseMove << QEvent::NonClientAreaMouseMove; + if (eventCategories & TouchEvents) { + m_eventTypes << QEvent::TouchBegin << QEvent::TouchUpdate << QEvent::TouchEnd; +#if QT_VERSION >= 0x050000 + m_eventTypes << QEvent::TouchCancel; +#endif + } + if (eventCategories & TabletEvents) { + m_eventTypes << QEvent::TabletEnterProximity << QEvent::TabletLeaveProximity + << QEvent::TabletMove << QEvent::TabletPress << QEvent::TabletRelease; + } + if (eventCategories & DragAndDropEvents) { + m_eventTypes << QEvent::DragEnter << QEvent::DragMove << QEvent::DragLeave + << QEvent::Drop << QEvent::DragResponse; + } + if (eventCategories & KeyEvents) { + m_eventTypes << QEvent::KeyPress << QEvent::KeyRelease << QEvent::ShortcutOverride + << QEvent::Shortcut; + } + if (eventCategories & GeometryEvents) + m_eventTypes << QEvent::Move << QEvent::Resize; + if (eventCategories & PaintEvents) { + m_eventTypes << QEvent::UpdateRequest << QEvent::Paint + << QEvent::Show << QEvent::Hide; +#if QT_VERSION >= 0x050000 + m_eventTypes << QEvent::Expose; +#endif + } + if (eventCategories & TimerEvents) + m_eventTypes << QEvent::Timer << QEvent::ZeroTimerEvent; + if (eventCategories & ObjectEvents) { + m_eventTypes << QEvent::ChildAdded << QEvent::ChildPolished + << QEvent::ChildRemoved << QEvent::Create << QEvent::Destroy; + } +} + +bool EventFilter::eventFilter(QObject *o, QEvent *e) +{ + static int n = 0; + if (m_eventTypes.contains(e->type())) { + QDebug debug = qDebug().nospace(); + const QString on = o->objectName(); + debug << '#' << n++ << ' ' << o->metaObject()->className(); + if (!on.isEmpty()) + debug << '/' << on; + debug << ' ' << e; + } + return false; +} + +} // namespace QtDiag diff --git a/tests/manual/diaglib/eventfilter.h b/tests/manual/diaglib/eventfilter.h new file mode 100644 index 0000000000..d87ac68b07 --- /dev/null +++ b/tests/manual/diaglib/eventfilter.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _EVENTFILTER_ +#define _EVENTFILTER_ + +#include +#include +#include + +namespace QtDiag { + +// Event filter that can for example be installed on QApplication +// to log relevant events. + +class EventFilter : public QObject { +public: + enum EventCategory { + MouseEvents = 0x00001, + MouseMoveEvents = 0x00002, + TouchEvents = 0x00004, + TabletEvents = 0x00008, + DragAndDropEvents = 0x00010, + KeyEvents = 0x00020, + GeometryEvents = 0x00040, + PaintEvents = 0x00080, + TimerEvents = 0x00100, + ObjectEvents = 0x00200 + }; + Q_DECLARE_FLAGS(EventCategories, EventCategory) + + explicit EventFilter(EventCategories eventCategories, QObject *p = 0); + explicit EventFilter(QObject *p = 0); + + bool eventFilter(QObject *, QEvent *); + +private: + void init(EventCategories eventCategories); + + QList m_eventTypes; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(EventFilter::EventCategories) + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/glinfo.cpp b/tests/manual/diaglib/glinfo.cpp new file mode 100644 index 0000000000..cd30e46b45 --- /dev/null +++ b/tests/manual/diaglib/glinfo.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "glinfo.h" + +#include +#include +#if QT_VERSION > 0x050000 +# if QT_VERSION >= 0x050400 +# include +# include +# else // 5.4 +# include +# endif // 5.0..5.4 +# include +# include +# include +#endif +#include +#include +#include + +namespace QtDiag { + +#if QT_VERSION > 0x050000 + +static QString getGlString(const QOpenGLContext *ctx, GLenum name) +{ + if (const GLubyte *p = ctx->functions()->glGetString(name)) + return QString::fromLatin1(reinterpret_cast(p)); + return QString(); +} + +static QString glInfo(const QOpenGLContext *ctx) +{ + return getGlString(ctx, GL_VENDOR) + + QLatin1Char('\n') + + getGlString(ctx, GL_RENDERER); +} + +static QString glInfo(const QGLContext *ctx) +{ + return glInfo(ctx->contextHandle()); +} + +QString glInfo(const QObject *o) +{ +# if QT_VERSION >= 0x050400 + if (o->isWindowType()) { + if (const QOpenGLWindow *oglw = qobject_cast(o)) + return glInfo(oglw->context()); + return QString(); + } +# endif // 5.4 + if (o->isWidgetType()) { + if (const QGLWidget *g = qobject_cast(o)) + return glInfo(g->context()); +# if QT_VERSION >= 0x050400 + if (const QOpenGLWidget *g = qobject_cast(o)) + return glInfo(g->context()); +# endif // 5.4 + } + return QString(); +} + +#else // Qt4: + +static QString getGlString(GLenum name) +{ + if (const GLubyte *p = glGetString(name)) + return QString::fromLatin1(reinterpret_cast(p)); + return QString(); +} + +QString glInfo(const QWidget *) +{ + return getGlString(GL_VENDOR) + QLatin1Char('\n') + getGlString(GL_RENDERER); +} + +#endif + +} // namespace QtDiag diff --git a/tests/manual/diaglib/glinfo.h b/tests/manual/diaglib/glinfo.h new file mode 100644 index 0000000000..1f515267f2 --- /dev/null +++ b/tests/manual/diaglib/glinfo.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _GLINFO_ +#define _GLINFO_ + +#include + +QT_FORWARD_DECLARE_CLASS(QObject) +QT_FORWARD_DECLARE_CLASS(QString) + +namespace QtDiag { + +QString glInfo(const QObject *o); + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/nativewindowdump.cpp b/tests/manual/diaglib/nativewindowdump.cpp new file mode 100644 index 0000000000..a6c741a085 --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump.cpp @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nativewindowdump.h" + +namespace QtDiag { + +void dumpNativeWindows(WId) +{ +} + +void dumpNativeQtTopLevels() +{ +} + +} // namespace QtDiag diff --git a/tests/manual/diaglib/nativewindowdump.h b/tests/manual/diaglib/nativewindowdump.h new file mode 100644 index 0000000000..405998feea --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _NATIVEWINDOWDUMP_ +#define _NATIVEWINDOWDUMP_ + +#include + +namespace QtDiag { + +void dumpNativeWindows(WId root = 0); +void dumpNativeQtTopLevels(); + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/nativewindowdump_win.cpp b/tests/manual/diaglib/nativewindowdump_win.cpp new file mode 100644 index 0000000000..814b580f4b --- /dev/null +++ b/tests/manual/diaglib/nativewindowdump_win.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nativewindowdump.h" +#include "qwindowdump.h" + +#include +#include +#include +#include + +#include + +namespace QtDiag { + +struct DumpContext { + DumpContext() : indentation(0) {} + + int indentation; + QSharedPointer stream; +}; + +#define debugWinStyle(str, style, styleConstant) \ +if (style & styleConstant) \ + str << ' ' << #styleConstant; + +static void formatNativeWindow(HWND hwnd, QTextStream &str) +{ + str << hex << showbase << quintptr(hwnd) << noshowbase << dec; + RECT rect; + if (GetWindowRect(hwnd, &rect)) { + str << ' ' << (rect.right - rect.left) << 'x' << (rect.bottom - rect.top) + << '+' << rect.left << '+' << rect.top; + } + if (IsWindowVisible(hwnd)) + str << " [visible]"; + + str << hex << showbase; + if (const LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE)) { + str << " style=" << style; + debugWinStyle(str, style, WS_OVERLAPPED) + debugWinStyle(str, style, WS_POPUP) + debugWinStyle(str, style, WS_MINIMIZE) + debugWinStyle(str, style, WS_CHILD) + debugWinStyle(str, style, WS_VISIBLE) + debugWinStyle(str, style, WS_DISABLED) + debugWinStyle(str, style, WS_CLIPSIBLINGS) + debugWinStyle(str, style, WS_CLIPCHILDREN) + debugWinStyle(str, style, WS_MAXIMIZE) + debugWinStyle(str, style, WS_CAPTION) + debugWinStyle(str, style, WS_BORDER) + debugWinStyle(str, style, WS_DLGFRAME) + debugWinStyle(str, style, WS_VSCROLL) + debugWinStyle(str, style, WS_HSCROLL) + debugWinStyle(str, style, WS_SYSMENU) + debugWinStyle(str, style, WS_THICKFRAME) + debugWinStyle(str, style, WS_GROUP) + debugWinStyle(str, style, WS_TABSTOP) + debugWinStyle(str, style, WS_MINIMIZEBOX) + debugWinStyle(str, style, WS_MAXIMIZEBOX) + } + if (const LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE)) { + str << " exStyle=" << exStyle; + debugWinStyle(str, exStyle, WS_EX_DLGMODALFRAME) + debugWinStyle(str, exStyle, WS_EX_NOPARENTNOTIFY) + debugWinStyle(str, exStyle, WS_EX_TOPMOST) + debugWinStyle(str, exStyle, WS_EX_ACCEPTFILES) + debugWinStyle(str, exStyle, WS_EX_TRANSPARENT) + debugWinStyle(str, exStyle, WS_EX_MDICHILD) + debugWinStyle(str, exStyle, WS_EX_TOOLWINDOW) + debugWinStyle(str, exStyle, WS_EX_WINDOWEDGE) + debugWinStyle(str, exStyle, WS_EX_CLIENTEDGE) + debugWinStyle(str, exStyle, WS_EX_CONTEXTHELP) + debugWinStyle(str, exStyle, WS_EX_RIGHT) + debugWinStyle(str, exStyle, WS_EX_LEFT) + debugWinStyle(str, exStyle, WS_EX_RTLREADING) + debugWinStyle(str, exStyle, WS_EX_LTRREADING) + debugWinStyle(str, exStyle, WS_EX_LEFTSCROLLBAR) + debugWinStyle(str, exStyle, WS_EX_RIGHTSCROLLBAR) + debugWinStyle(str, exStyle, WS_EX_CONTROLPARENT) + debugWinStyle(str, exStyle, WS_EX_STATICEDGE) + debugWinStyle(str, exStyle, WS_EX_APPWINDOW) + debugWinStyle(str, exStyle, WS_EX_LAYERED) + debugWinStyle(str, exStyle, WS_EX_NOINHERITLAYOUT) + debugWinStyle(str, exStyle, WS_EX_NOREDIRECTIONBITMAP) + debugWinStyle(str, exStyle, WS_EX_LAYOUTRTL) + debugWinStyle(str, exStyle, WS_EX_COMPOSITED) + debugWinStyle(str, exStyle, WS_EX_NOACTIVATE) + } + str << noshowbase << dec; + + wchar_t buf[512]; + if (GetWindowText(hwnd, buf, sizeof(buf)/sizeof(buf[0]))) + str << " title=\"" << QString::fromWCharArray(buf) << '"'; + if (GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0]))) + str << " class=\"" << QString::fromWCharArray(buf) << '"'; + str << '\n'; +} + +static void dumpNativeWindowRecursion(HWND hwnd, DumpContext *dc); + +BOOL CALLBACK dumpWindowEnumChildProc(HWND hwnd, LPARAM lParam) +{ + dumpNativeWindowRecursion(hwnd, reinterpret_cast(lParam)); + return TRUE; +} + +static void dumpNativeWindowRecursion(HWND hwnd, DumpContext *dc) +{ + indentStream(*dc->stream, dc->indentation); + formatNativeWindow(hwnd, *dc->stream); + DumpContext nextLevel = *dc; + nextLevel.indentation += 2; + EnumChildWindows(hwnd, dumpWindowEnumChildProc, reinterpret_cast(&nextLevel)); +} + +/* recurse by Z order, same result */ +static void dumpNativeWindowRecursionByZ(HWND hwnd, DumpContext *dc) +{ + indentStream(*dc->stream, dc->indentation); + formatNativeWindow(hwnd, *dc->stream); + if (const HWND topChild = GetTopWindow(hwnd)) { + DumpContext nextLevel = *dc; + nextLevel.indentation += 2; + for (HWND child = topChild; child ; child = GetNextWindow(child, GW_HWNDNEXT)) + dumpNativeWindowRecursionByZ(child, &nextLevel); + } +} + +typedef QVector WIdVector; + +static void dumpNativeWindows(const WIdVector& wins) +{ + DumpContext dc; + QString s; + dc.stream = QSharedPointer(new QTextStream(&s)); + foreach (WId win, wins) + dumpNativeWindowRecursion(reinterpret_cast(win), &dc); +#if QT_VERSION > 0x050000 + qDebug().noquote() << s; +#else + qDebug("%s", qPrintable(s)); +#endif +} + +void dumpNativeWindows(WId rootIn) +{ + const WId root = rootIn ? rootIn : reinterpret_cast(GetDesktopWindow()); + dumpNativeWindows(WIdVector(1, root)); +} + +BOOL CALLBACK findQtTopLevelEnumChildProc(HWND hwnd, LPARAM lParam) +{ + WIdVector *v = reinterpret_cast(lParam); + wchar_t buf[512]; + if (GetClassName(hwnd, buf, sizeof(buf)/sizeof(buf[0]))) { + if (wcsstr(buf, L"Qt")) + v->append(reinterpret_cast(hwnd)); + } + return TRUE; +} + +static WIdVector findQtTopLevels() +{ + WIdVector result; + EnumChildWindows(GetDesktopWindow(), + findQtTopLevelEnumChildProc, + reinterpret_cast(&result)); + return result; +} + +void dumpNativeQtTopLevels() +{ + dumpNativeWindows(findQtTopLevels()); +} + +} // namespace QtDiag diff --git a/tests/manual/diaglib/qwidgetdump.cpp b/tests/manual/diaglib/qwidgetdump.cpp new file mode 100644 index 0000000000..d4f985c7c8 --- /dev/null +++ b/tests/manual/diaglib/qwidgetdump.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidgetdump.h" + +#include +#if QT_VERSION > 0x050000 +# include +# include +#endif +#include +#include +#include +#include + +namespace QtDiag { + +static void dumpWidgetRecursion(QTextStream &str, const QWidget *w, + FormatWindowOptions options, int depth = 0) +{ + indentStream(str, 2 * depth); + formatObject(str, w); + str << ' ' << (w->isVisible() ? "[visible] " : "[hidden] "); + if (const WId nativeWinId = w->internalWinId()) + str << "[native: " << hex << showbase << nativeWinId << dec << noshowbase << "] "; + if (w->isWindow()) + str << "[top] "; + str << (w->testAttribute(Qt::WA_Mapped) ? "[mapped] " : "[not mapped] "); + if (w->testAttribute(Qt::WA_DontCreateNativeAncestors)) + str << "[NoNativeAncestors] "; + formatRect(str, w->geometry()); + if (!(options & DontPrintWindowFlags)) { + str << ' '; + formatWindowFlags(str, w->windowFlags()); + } + str << '\n'; +#if QT_VERSION > 0x050000 + if (const QWindow *win = w->windowHandle()) { + indentStream(str, 2 * (1 + depth)); + formatWindow(str, win, options); + str << '\n'; + } +#endif // Qt 5 + foreach (const QObject *co, w->children()) { + if (co->isWidgetType()) + dumpWidgetRecursion(str, static_cast(co), options, depth + 1); + } +} + +void dumpAllWidgets(FormatWindowOptions options) +{ + QString d; + QTextStream str(&d); + str << "### QWidgets:\n"; + foreach (QWidget *tw, QApplication::topLevelWidgets()) + dumpWidgetRecursion(str, tw, options); +#if QT_VERSION > 0x050000 + qDebug().noquote() << d; +#else + qDebug("%s", qPrintable(d)); +#endif +} + +} // namespace QtDiag diff --git a/tests/manual/diaglib/qwidgetdump.h b/tests/manual/diaglib/qwidgetdump.h new file mode 100644 index 0000000000..f9615b5d2f --- /dev/null +++ b/tests/manual/diaglib/qwidgetdump.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _WIDGETDUMP_ +#define _WIDGETDUMP_ + +#include "qwindowdump.h" + +namespace QtDiag { + +void dumpAllWidgets(FormatWindowOptions options = 0); + +} // namespace QtDiag + +#endif diff --git a/tests/manual/diaglib/qwindowdump.cpp b/tests/manual/diaglib/qwindowdump.cpp new file mode 100644 index 0000000000..2ecc52ca77 --- /dev/null +++ b/tests/manual/diaglib/qwindowdump.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowdump.h" + +#if QT_VERSION > 0x050000 +# include +# include +# include +# include +#endif +#include +#include +#include +#include + +namespace QtDiag { + +void indentStream(QTextStream &s, int indent) +{ + for (int i = 0; i < indent; ++i) + s << ' '; +} + +void formatObject(QTextStream &str, const QObject *o) +{ + str << o->metaObject()->className(); + const QString on = o->objectName(); + if (!on.isEmpty()) + str << "/\"" << on << '"'; +} + +void formatRect(QTextStream &str, const QRect &geom) +{ + str << geom.width() << 'x' << geom.height() + << forcesign << geom.x() << geom.y() << noforcesign; +} + +#define debugType(s, type, typeConstant) \ +if ((type & typeConstant) == typeConstant) \ + s << ' ' << #typeConstant; + +#define debugFlag(s, flags, flagConstant) \ +if (flags & flagConstant) \ + s << ' ' << #flagConstant; + +void formatWindowFlags(QTextStream &str, const Qt::WindowFlags flags) +{ + str << showbase << hex << unsigned(flags) << dec << noshowbase; + const Qt::WindowFlags windowType = flags & Qt::WindowType_Mask; + debugFlag(str, flags, Qt::Window) + debugType(str, windowType, Qt::Dialog) + debugType(str, windowType, Qt::Sheet) + debugType(str, windowType, Qt::Drawer) + debugType(str, windowType, Qt::Popup) + debugType(str, windowType, Qt::Tool) + debugType(str, windowType, Qt::ToolTip) + debugType(str, windowType, Qt::SplashScreen) + debugType(str, windowType, Qt::Desktop) + debugType(str, windowType, Qt::SubWindow) +#if QT_VERSION > 0x050000 + debugType(str, windowType, Qt::ForeignWindow) + debugType(str, windowType, Qt::CoverWindow) +#endif + debugFlag(str, flags, Qt::MSWindowsFixedSizeDialogHint) + debugFlag(str, flags, Qt::MSWindowsOwnDC) + debugFlag(str, flags, Qt::X11BypassWindowManagerHint) + debugFlag(str, flags, Qt::FramelessWindowHint) + debugFlag(str, flags, Qt::WindowTitleHint) + debugFlag(str, flags, Qt::WindowSystemMenuHint) + debugFlag(str, flags, Qt::WindowMinimizeButtonHint) + debugFlag(str, flags, Qt::WindowMaximizeButtonHint) + debugFlag(str, flags, Qt::WindowContextHelpButtonHint) + debugFlag(str, flags, Qt::WindowShadeButtonHint) + debugFlag(str, flags, Qt::WindowStaysOnTopHint) + debugFlag(str, flags, Qt::CustomizeWindowHint) +#if QT_VERSION > 0x050000 + debugFlag(str, flags, Qt::WindowTransparentForInput) + debugFlag(str, flags, Qt::WindowOverridesSystemGestures) + debugFlag(str, flags, Qt::WindowDoesNotAcceptFocus) + debugFlag(str, flags, Qt::NoDropShadowWindowHint) + debugFlag(str, flags, Qt::WindowFullscreenButtonHint) +#endif + debugFlag(str, flags, Qt::WindowStaysOnBottomHint) + debugFlag(str, flags, Qt::MacWindowToolBarButtonHint) + debugFlag(str, flags, Qt::BypassGraphicsProxyWidget) + debugFlag(str, flags, Qt::WindowOkButtonHint) + debugFlag(str, flags, Qt::WindowCancelButtonHint) +} + +#if QT_VERSION > 0x050000 + +void formatWindow(QTextStream &str, const QWindow *w, FormatWindowOptions options) +{ + const QPlatformWindow *pw = w->handle(); + formatObject(str, w); + str << ' ' << (w->isVisible() ? "[visible] " : "[hidden] "); + if (const WId nativeWinId = pw ? pw->winId() : WId(0)) + str << "[native: " << hex << showbase << nativeWinId << dec << noshowbase << "] "; + if (w->isTopLevel()) + str << "[top] "; + if (w->isExposed()) + str << "[exposed] "; + formatRect(str, w->geometry()); + if (!(options & DontPrintWindowFlags)) { + str << ' '; + formatWindowFlags(str, w->flags()); + } + str << '\n'; +} + +static void dumpWindowRecursion(QTextStream &str, const QWindow *w, + FormatWindowOptions options = 0, int depth = 0) +{ + indentStream(str, 2 * depth); + formatWindow(str, w); + foreach (const QObject *co, w->children()) { + if (co->isWindowType()) + dumpWindowRecursion(str, static_cast(co), options, depth + 1); + } +} + +void dumpAllWindows(FormatWindowOptions options) +{ + QString d; + QTextStream str(&d); + str << "### QWindows:\n"; + foreach (QWindow *w, QGuiApplication::topLevelWindows()) + dumpWindowRecursion(str, w, options); + qDebug().noquote() << d; +} + +#else // Qt 5 +class QWindow {}; + +void formatWindow(QTextStream &, const QWindow *, FormatWindowOptions) +{ +} + +void dumpAllWindows(FormatWindowOptions options) +{ +} + +#endif // Qt 4 + +} // namespace QtDiag diff --git a/tests/manual/diaglib/qwindowdump.h b/tests/manual/diaglib/qwindowdump.h new file mode 100644 index 0000000000..ab7c0243e9 --- /dev/null +++ b/tests/manual/diaglib/qwindowdump.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _WINDOWDUMP_ +#define _WINDOWDUMP_ + +#include + +QT_FORWARD_DECLARE_CLASS(QRect) +QT_FORWARD_DECLARE_CLASS(QObject) +QT_FORWARD_DECLARE_CLASS(QWindow) +QT_FORWARD_DECLARE_CLASS(QTextStream) + +namespace QtDiag { + +enum FormatWindowOption { + DontPrintWindowFlags = 0x001 +}; + +Q_DECLARE_FLAGS(FormatWindowOptions, FormatWindowOption) +Q_DECLARE_OPERATORS_FOR_FLAGS(FormatWindowOptions) + +void indentStream(QTextStream &s, int indent); +void formatObject(QTextStream &str, const QObject *o); +void formatRect(QTextStream &str, const QRect &geom); +void formatWindowFlags(QTextStream &str, const Qt::WindowFlags flags); + +void formatWindow(QTextStream &str, const QWindow *w, FormatWindowOptions options = 0); +void dumpAllWindows(FormatWindowOptions options = 0); + +} // namespace QtDiag + +#endif From 4f3a1f49680fa53186b2f2673d26fc6bc3288a94 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 11 Nov 2014 18:26:06 +0100 Subject: [PATCH 218/323] remove nonsensical claim about contains() the string is implicitly anchored, so "foo" does of course not match "no-foo". this allows us to de-noise the generated qfeatures.pri somewhat. it still makes sense not to auto-include that file for performance reasons, so this change is a functional no-op. Change-Id: Ied75fd6459022c0b8c80843d62c4ab9eba9bf261 Reviewed-by: Joerg Bornemann --- qtbase.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qtbase.pro b/qtbase.pro index d6861cf09f..6d0de44f6d 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -140,7 +140,7 @@ for (ft, features) { "$${LITERAL_HASH} define QT_NO_$$ft" \ "$${LITERAL_HASH}endif" FEATURES_PRI += \ - "contains(QT_DISABLED_FEATURES, "^($$lower($$join($$list($$replace(features.$${ft}.depends, _, -)), "|")))$"): \\" \ + "contains(QT_DISABLED_FEATURES, "$$lower($$join($$list($$replace(features.$${ft}.depends, _, -)), "|"))"): \\" \ " QT_DISABLED_FEATURES += $$lower($$replace(ft, _, -))" } } @@ -168,7 +168,8 @@ for (def, QT_NO_DEFINES) { } no_features = $$unique(no_features) -# Can't simply add these to QT_CONFIG, as e.g., contains(QT_CONFIG, accessibility) matches no-accessibililty. +# Don't simply add these to QT_CONFIG, as then one might expect them to be there without load(qfeatures). +# And we don't want to do that automatically, as the dynamic dependency resolution is somewhat expensive. FEATURES_PRI = \ "$${LITERAL_HASH} Features disabled by configure:" \ "QT_DISABLED_FEATURES =$$lower($$join($$list($$replace(no_features, _, -)), " ", " "))" \ From 1e0516fc69296bea7f4498127b5bd425cba15ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Thu, 13 Nov 2014 15:05:03 +0100 Subject: [PATCH 219/323] Add C++11 if available for QVariant autotest gcc 4.9 has the __has_include feature which enables the TEST_FORWARD_LIST and includes the forward_list header. This in turn checks that the c++11 flags are enabled, or throws an error. Change-Id: I44aa58e47c2f9ba6f14cb5a68d24da4a76698e5f Reviewed-by: Olivier Goffart --- tests/auto/corelib/kernel/qvariant/qvariant.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/corelib/kernel/qvariant/qvariant.pro b/tests/auto/corelib/kernel/qvariant/qvariant.pro index f8d054f70c..39178ba9e6 100644 --- a/tests/auto/corelib/kernel/qvariant/qvariant.pro +++ b/tests/auto/corelib/kernel/qvariant/qvariant.pro @@ -6,3 +6,4 @@ INCLUDEPATH += $$PWD/../../../other/qvariant_common SOURCES = tst_qvariant.cpp RESOURCES += qvariant.qrc DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 +contains(QT_CONFIG, c++11): CONFIG += c++11 From ea8d4869b722f0eca2b7bbbdd77ac7e3a13ccd10 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 7 Nov 2014 09:32:11 +0100 Subject: [PATCH 220/323] a widget's window is transient for its parent's top-level window When a widget's parent's window is not a top-level window, it should find the top-level window before calling setTransientParent, to avoid a warning (since a71e285133087714034f3c84a758980c85b3801e). Task-number: QTBUG-42464 Change-Id: I732691b0d40aba226470332426775d1bd4381009 Reviewed-by: Friedemann Kleint Reviewed-by: Laszlo Agocs --- src/widgets/kernel/qwidget.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 315d615d89..78eabf3c4c 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -10511,8 +10511,9 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f) QWidget *parentWithWindow = newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : 0; if (parentWithWindow) { - if (f & Qt::Window) { - q->windowHandle()->setTransientParent(parentWithWindow->windowHandle()); + QWidget *topLevel = parentWithWindow->window(); + if ((f & Qt::Window) && topLevel && topLevel->windowHandle()) { + q->windowHandle()->setTransientParent(topLevel->windowHandle()); q->windowHandle()->setParent(0); } else { q->windowHandle()->setTransientParent(0); From 63f5b1a7fccca3cf8d7082eeffec31a15cc36de7 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 5 Nov 2014 14:51:06 +0100 Subject: [PATCH 221/323] send touch update when more points begin after single touch is ignored Otherwise, a widget can't detect pinches if the points don't start simultaneously unless it sets WA_TouchPadAcceptSingleTouchEvents. The use case is for a widget that doesn't actually want the single touch events, but only when there are two or more touchpoints. Task-number: QTBUG-42389 Change-Id: I5269d9acb93a0001c4fde02b1f7b9e0dfcc0032f Reviewed-by: Laszlo Agocs --- src/widgets/kernel/qapplication.cpp | 12 ++++++++++-- src/widgets/kernel/qapplication_p.h | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 8f6c5d748c..269fe452c1 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -4230,8 +4230,9 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } -void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +bool QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) { + bool containsPress = false; for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { QTouchEvent::TouchPoint &touchPoint = touchEvent->_touchPoints[i]; @@ -4244,7 +4245,11 @@ void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEven touchPoint.d->rect = rect; touchPoint.d->startPos = widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta; touchPoint.d->lastPos = widget->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta; + + if (touchPoint.state() == Qt::TouchPointPressed) + containsPress = true; } + return containsPress; } void QApplicationPrivate::initializeMultitouch() @@ -4391,11 +4396,14 @@ bool QApplicationPrivate::translateRawTouchEvent(QWidget *window, QApplication::keyboardModifiers(), it.value().first, it.value().second); - updateTouchPointsForWidget(widget, &touchEvent); + bool containsPress = updateTouchPointsForWidget(widget, &touchEvent); touchEvent.setTimestamp(timestamp); touchEvent.setWindow(window->windowHandle()); touchEvent.setTarget(widget); + if (containsPress) + widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent); + switch (touchEvent.type()) { case QEvent::TouchBegin: { diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 156bf34194..7d97235c66 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -275,7 +275,7 @@ public: QPixmap *ignore_cursor; #endif - static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + static bool updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); void initializeMultitouch(); void initializeMultitouch_sys(); void cleanupMultitouch(); From eca0668a8c76cc5ea273f614500e91de7e706541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Thu, 6 Nov 2014 16:14:32 +0100 Subject: [PATCH 222/323] iOS: Ensure that the rename-main logic works for multi-arch builds We need to tell Xcode which architectures it should set up pre-link dependencies for, as well as run the rename script in the root object file directory. We pass it the current architectures so that we only rename main() for simulator or device, not both. Change-Id: I095d7c8a22ff0cb2ce872c9a86c93a070c1fcc65 Reviewed-by: Oswald Buddenhagen Reviewed-by: Richard Moe Gustavsen --- mkspecs/macx-ios-clang/features/default_post.prf | 2 +- mkspecs/macx-ios-clang/features/qt.prf | 6 ++++-- mkspecs/macx-ios-clang/rename_main.sh | 10 +++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 51a87e3eab..5da95f16bf 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -201,7 +201,7 @@ macx-xcode { arch_iphonesimulator.value = $$QMAKE_IOS_SIMULATOR_ARCHS QMAKE_MAC_XCODE_SETTINGS += arch_iphoneos arch_iphonesimulator - unset(QMAKE_XCODE_ARCHS) + QMAKE_XCODE_ARCHS = $$QMAKE_IOS_DEVICE_ARCHS $$QMAKE_IOS_SIMULATOR_ARCHS } else { # Be more specific about which architecture we're targeting contains(QT_ARCH, arm.*): \ diff --git a/mkspecs/macx-ios-clang/features/qt.prf b/mkspecs/macx-ios-clang/features/qt.prf index a5b00377ee..7ca3198dbe 100644 --- a/mkspecs/macx-ios-clang/features/qt.prf +++ b/mkspecs/macx-ios-clang/features/qt.prf @@ -32,17 +32,19 @@ equals(TEMPLATE, app):contains(QT, gui(-private)?) { # called 'qt_main' now. macx-xcode { - objects_dir = "${OBJECT_FILE_DIR}-${CURRENT_VARIANT}/${CURRENT_ARCH}" + objects_dir = "${OBJECT_FILE_DIR}-${CURRENT_VARIANT}" + archs = "${ARCHS}" } else { objects_dir = $$OBJECTS_DIR isEmpty(objects_dir): \ objects_dir = . + archs = "$$QMAKE_IOS_DEVICE_ARCHS $$QMAKE_IOS_SIMULATOR_ARCHS" } !isEmpty(QMAKE_PRE_LINK): \ QMAKE_PRE_LINK += ";" - QMAKE_PRE_LINK += $$QMAKESPEC/rename_main.sh $${objects_dir} + QMAKE_PRE_LINK += $$QMAKESPEC/rename_main.sh $${objects_dir} \"$${archs}\" } } diff --git a/mkspecs/macx-ios-clang/rename_main.sh b/mkspecs/macx-ios-clang/rename_main.sh index b1321e855e..040140b7ee 100755 --- a/mkspecs/macx-ios-clang/rename_main.sh +++ b/mkspecs/macx-ios-clang/rename_main.sh @@ -41,10 +41,14 @@ ## ############################################################################# -if [ $# -eq 0 ]; then - echo "usage: $0 " +if [ $# -ne 2 ]; then + echo "$0: wrong number of arguments for internal tool used by iOS mkspec" else - for f in $(find $1 -name '*.o'); do + arch_paths="" + for a in $2; do + arch_paths="$arch_paths $1/$a" + done + for f in $(find $arch_paths -name '*.o'); do # Skip object files without the _main symbol nm $f 2>/dev/null | grep -q 'T _main$' || continue From 88b2f5e8686ee7b1b7f49012c964f2ec20d6c61e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 4 Nov 2014 19:41:48 +0100 Subject: [PATCH 223/323] iOS: Allow ARCHS to be specified at build time for multi-arch builds Building all architectures of a multi-arch build during Qt development is in most cases not needed, so we expose a way to limit the archs we build by passing ARCHS="subset of archs" to make, similar to how you can pass ARCHS to xcodebuild. If the subset doesn't match any of the valid architectures for the target, it will fall back to the default architectures, so it's safe to pass eg. ARCHS="armv7 i386" to make, even if building for both simulator and device. The variable may also be exported to the environment for more persistent limits on which architectures to build. Change-Id: I47b10bc9d743f0301efff4181d6881ae140d557f Reviewed-by: Richard Moe Gustavsen --- mkspecs/macx-ios-clang/features/default_post.prf | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 5da95f16bf..34fbac56d0 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -205,18 +205,21 @@ macx-xcode { } else { # Be more specific about which architecture we're targeting contains(QT_ARCH, arm.*): \ - actual_archs = $$QMAKE_IOS_DEVICE_ARCHS + VALID_ARCHS = $$QMAKE_IOS_DEVICE_ARCHS else: \ - actual_archs = $$QMAKE_IOS_SIMULATOR_ARCHS + VALID_ARCHS = $$QMAKE_IOS_SIMULATOR_ARCHS - for(arch, actual_archs): \ - arch_flags += -arch $$arch + ACTIVE_ARCHS = $(filter $(EXPORT_VALID_ARCHS), $(ARCHS)) + ARCH_ARGS = $(foreach arch, $(if $(EXPORT_ACTIVE_ARCHS), $(EXPORT_ACTIVE_ARCHS), $(EXPORT_VALID_ARCHS)), -arch $(arch)) + + QMAKE_EXTRA_VARIABLES += VALID_ARCHS ACTIVE_ARCHS ARCH_ARGS + + arch_flags = $(EXPORT_ARCH_ARGS) QMAKE_CFLAGS += $$arch_flags QMAKE_CXXFLAGS += $$arch_flags QMAKE_OBJECTIVE_CFLAGS += $$arch_flags QMAKE_LFLAGS += $$arch_flags } -unset(actual_archs) load(default_post) From 70ea4e2b294eeac51fc497191990842f48d1aff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 28 Oct 2014 13:27:25 +0100 Subject: [PATCH 224/323] iOS: Enable fat builds containing both armv7 and arm64 slices Apple will from February 1, 2015, require all applications uploaded to the App Store to be built for both 32-bit (armv7/s) and 64-bit (arm64). https://developer.apple.com/news/?id=10202014a We enable fat Qt binaries by passing both -arch armv7 and -arch arm64 to clang, which takes care of lipoing together the two slices for each object file. This unfortunately means twice the build time and twice the binary size for our libraries. Since precompiled headers are architecture specific, and the -Xarch option can't be used with -include-pch, we need to disable precompiled headers globally. This can be improved in the future by switching to pretokenized headers (http://clang.llvm.org/docs/PTHInternals.html). Since we're enabling 64-bit ARM builds, we're also switching the simulator builds from i386 to fat i386 and x86_64 builds, so that we are able to test 64-bit builds using the simulator, but we're keeping i386 as the architecture Qt is aware of when it's building for simulator, as we need the CPU features to match the lowest common denominator. Change-Id: I277e60bddae549d24ca3c6301d842405180aded6 Reviewed-by: Simon Hausmann --- configure | 1 + mkspecs/macx-ios-clang/features/default_post.prf | 2 ++ mkspecs/macx-ios-clang/features/qt_config.prf | 4 ++++ mkspecs/macx-ios-clang/qmake.conf | 4 ++-- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 1bd7db88b3..979e32e050 100755 --- a/configure +++ b/configure @@ -3152,6 +3152,7 @@ if [ "$XPLATFORM_IOS" = "yes" ]; then CFG_NOBUILD_PARTS="$CFG_NOBUILD_PARTS examples" CFG_SHARED="no" # iOS builds should be static to be able to submit to the App Store CFG_SKIP_MODULES="$CFG_SKIP_MODULES qtconnectivity qtdoc qtmacextras qtserialport qtwebkit qtwebkit-examples" + CFG_PRECOMPILE="no" # Precompiled headers not supported with multiple -arch arguments # If the user passes -sdk on the command line we build a SDK-specific Qt build. # Otherwise we build a joined simulator and device build, which is the default. diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 34fbac56d0..0245c948d9 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -209,6 +209,8 @@ macx-xcode { else: \ VALID_ARCHS = $$QMAKE_IOS_SIMULATOR_ARCHS + single_arch: VALID_ARCHS = $$first(VALID_ARCHS) + ACTIVE_ARCHS = $(filter $(EXPORT_VALID_ARCHS), $(ARCHS)) ARCH_ARGS = $(foreach arch, $(if $(EXPORT_ACTIVE_ARCHS), $(EXPORT_ACTIVE_ARCHS), $(EXPORT_VALID_ARCHS)), -arch $(arch)) diff --git a/mkspecs/macx-ios-clang/features/qt_config.prf b/mkspecs/macx-ios-clang/features/qt_config.prf index d9a13f65eb..d1a1a36933 100644 --- a/mkspecs/macx-ios-clang/features/qt_config.prf +++ b/mkspecs/macx-ios-clang/features/qt_config.prf @@ -9,4 +9,8 @@ isEmpty(QT_ARCH) { QT_ARCH = arm else: \ # Simulator QT_ARCH = i386 + + # Prevent the arch/config tests from building as multi-arch binaries, + # as we only want the lowest common denominator features. + CONFIG += single_arch } diff --git a/mkspecs/macx-ios-clang/qmake.conf b/mkspecs/macx-ios-clang/qmake.conf index 7b2e7a17e7..0c083edf80 100644 --- a/mkspecs/macx-ios-clang/qmake.conf +++ b/mkspecs/macx-ios-clang/qmake.conf @@ -15,8 +15,8 @@ DEFINES += DARWIN_NO_CARBON QT_NO_PRINTER QT_NO_PRINTDIALOG # Universal target (iPhone and iPad) QMAKE_IOS_TARGETED_DEVICE_FAMILY = 1,2 -QMAKE_IOS_DEVICE_ARCHS = armv7 -QMAKE_IOS_SIMULATOR_ARCHS = i386 +QMAKE_IOS_DEVICE_ARCHS = armv7 arm64 +QMAKE_IOS_SIMULATOR_ARCHS = i386 x86_64 include(../common/ios.conf) include(../common/gcc-base-mac.conf) From 9afb02412eadc567e82a0aca10c6401937d213e9 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 13 Nov 2014 13:00:11 +0100 Subject: [PATCH 225/323] Revert "Fix fallbacks for adapted common script" This reverts 1dd9a0af4f577ccb5578cea562a98686c8e290e6. It was a band-aid for a change in the unicode itemizing algorithm which caused the script of a script item to become unreliable. This change has since been reverted, so the band-aid is no longer needed, and it also causes problems for WebKit on Windows when it ends up preferring Arial Unicode MS as the font for Uchen script, even though the font does not support this script. The autotest from the reverted commit is kept in place and still passes. [ChangeLog][Text] Fixed regression when rendering Uchen text in WebKit on Windows. Change-Id: I488c84703bb55a050d90092c6bf9e5c70a9e31c2 Task-number: QTBUG-41372 Reviewed-by: Allan Sandfeld Jensen --- src/gui/text/qfontdatabase.cpp | 10 +++++----- src/gui/text/qfontdatabase.h | 2 +- src/gui/text/qfontengine.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 1322a088e0..645d86c0fe 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -593,7 +593,7 @@ struct QtFontDesc static int match(int script, const QFontDef &request, const QString &family_name, const QString &foundry_name, int force_encoding_id, - QtFontDesc *desc, const QList &blacklisted, bool fallback); + QtFontDesc *desc, const QList &blacklisted); static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi) { @@ -1083,7 +1083,7 @@ static bool matchFamilyName(const QString &familyName, QtFontFamily *f) */ static int match(int script, const QFontDef &request, const QString &family_name, const QString &foundry_name, int force_encoding_id, - QtFontDesc *desc, const QList &blacklistedFamilies, bool fallback = false) + QtFontDesc *desc, const QList &blacklistedFamilies) { Q_UNUSED(force_encoding_id); int result = -1; @@ -1136,7 +1136,7 @@ static int match(int script, const QFontDef &request, load(test.family->name, script); // Check if family is supported in the script we want - if (!fallback && script != QChar::Script_Common && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported)) + if (script != QChar::Script_Common && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported)) continue; // as we know the script is supported, we can be sure @@ -2454,7 +2454,7 @@ bool QFontDatabase::supportsThreadedFontRendering() */ QFontEngine * QFontDatabase::findFont(int script, const QFontPrivate *fp, - const QFontDef &request, bool multi, bool fallback) + const QFontDef &request, bool multi) { QMutexLocker locker(fontDatabaseMutex()); @@ -2482,7 +2482,7 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp, QtFontDesc desc; QList blackListed; - int index = match(script, request, family_name, foundry_name, force_encoding_id, &desc, blackListed, fallback); + int index = match(script, request, family_name, foundry_name, force_encoding_id, &desc, blackListed); if (index >= 0) { engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size); if (!engine) diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index f1c479d0bb..d7d8745f12 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -152,7 +152,7 @@ private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); static QString resolveFontFamilyAlias(const QString &family); - static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request, bool multi = false, bool fallback = false); + static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request, bool multi = false); static void load(const QFontPrivate *d, int script); friend struct QFontDef; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 6a34a4c117..52e10bd717 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -2037,7 +2037,7 @@ void QFontEngineMultiBasicImpl::loadEngine(int at) request.family = fallbackFamilies.at(at-1); engines[at] = QFontDatabase::findFont(script, /*fontprivate = */0, - request, /*multi = */false, true); + request, /*multi = */false); Q_ASSERT(engines[at]); engines[at]->ref.ref(); engines[at]->fontDef = request; From be64d905a01ec364cfc630d86b6118f20e9df30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= Date: Tue, 11 Nov 2014 16:28:43 +0200 Subject: [PATCH 226/323] Set correct QSurfaceFormat also for raster surfacetype Change-Id: Idd37942842dc59ae391b6b34308d4c01e7a25bc5 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/qeglfswindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index c83b894089..f5839e086d 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -103,7 +103,7 @@ void QEglFSWindow::create() if (isRaster()) { QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); - context->setFormat(window()->requestedFormat()); + context->setFormat(m_format); context->setScreen(window()->screen()); if (!context->create()) qFatal("EGLFS: Failed to create compositing context"); From 4b717026d3e6b891ba14ae90394bc81e2514ffda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= Date: Wed, 8 Oct 2014 15:11:57 +0300 Subject: [PATCH 227/323] eglfs: ifdef linux specific functionality from convenience functions Because change a093204f07f276bc8e7b4fedf4af0e1369f55734 qeglfshooks_stub.cpp don't compile anymore on any other *nix platform than linux as those functions have been set linux specific only. Change-Id: I339672b1bf2745511076030cc1fe13dc7f2356ff Reviewed-by: Laszlo Agocs --- .../eglconvenience/qeglconvenience.cpp | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index 1fdeec3adb..c1a491c80b 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -37,8 +37,8 @@ #ifdef Q_OS_LINUX #include #include -#include #endif +#include #include "qeglconvenience_p.h" @@ -448,10 +448,13 @@ void q_printEglConfig(EGLDisplay display, EGLConfig config) } } -#ifdef Q_OS_LINUX +#ifdef Q_OS_UNIX QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize) { +#ifndef Q_OS_LINUX + Q_UNUSED(framebufferDevice) +#endif const int defaultPhysicalDpi = 100; static QSizeF size; @@ -466,10 +469,11 @@ QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize return size; } - struct fb_var_screeninfo vinfo; int w = -1; int h = -1; QSize screenResolution; +#ifdef Q_OS_LINUX + struct fb_var_screeninfo vinfo; if (framebufferDevice != -1) { if (ioctl(framebufferDevice, FBIOGET_VSCREENINFO, &vinfo) == -1) { @@ -479,7 +483,9 @@ QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize h = vinfo.height; screenResolution = QSize(vinfo.xres, vinfo.yres); } - } else { + } else +#endif + { // Use the provided screen size, when available, since some platforms may have their own // specific way to query it. Otherwise try querying it from the framebuffer. screenResolution = screenSize.isEmpty() ? q_screenSizeFromFb(framebufferDevice) : screenSize; @@ -499,6 +505,9 @@ QSizeF q_physicalScreenSizeFromFb(int framebufferDevice, const QSize &screenSize QSize q_screenSizeFromFb(int framebufferDevice) { +#ifndef Q_OS_LINUX + Q_UNUSED(framebufferDevice) +#endif const int defaultWidth = 800; const int defaultHeight = 600; static QSize size; @@ -513,6 +522,7 @@ QSize q_screenSizeFromFb(int framebufferDevice) return size; } +#ifdef Q_OS_LINUX struct fb_var_screeninfo vinfo; int xres = -1; int yres = -1; @@ -528,6 +538,10 @@ QSize q_screenSizeFromFb(int framebufferDevice) size.setWidth(xres <= 0 ? defaultWidth : xres); size.setHeight(yres <= 0 ? defaultHeight : yres); +#else + size.setWidth(defaultWidth); + size.setHeight(defaultHeight); +#endif } return size; @@ -535,10 +549,14 @@ QSize q_screenSizeFromFb(int framebufferDevice) int q_screenDepthFromFb(int framebufferDevice) { +#ifndef Q_OS_LINUX + Q_UNUSED(framebufferDevice) +#endif const int defaultDepth = 32; static int depth = qgetenv("QT_QPA_EGLFS_DEPTH").toInt(); if (depth == 0) { +#ifdef Q_OS_LINUX struct fb_var_screeninfo vinfo; if (framebufferDevice != -1) { @@ -550,11 +568,14 @@ int q_screenDepthFromFb(int framebufferDevice) if (depth <= 0) depth = defaultDepth; +#else + depth = defaultDepth; +#endif } return depth; } -#endif // Q_OS_LINUX +#endif // Q_OS_UNIX QT_END_NAMESPACE From eb05bda4f2fc1b9abe0c91d0b9e52c9633f5fff5 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 13 Nov 2014 10:56:02 +0100 Subject: [PATCH 228/323] QJsonArray::(const_)iterator: add the typedef for the pointer type Mandatory as per the standard iterator requirements, was causing compilation errors in the STL algorithms. Task-number: QTBUG-41628 Change-Id: Iee12a3b822383f63c07e270244fd0e145a486b95 Reviewed-by: Lars Knoll --- src/corelib/json/qjsonarray.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/json/qjsonarray.h b/src/corelib/json/qjsonarray.h index 87d14a7703..a8307ae5aa 100644 --- a/src/corelib/json/qjsonarray.h +++ b/src/corelib/json/qjsonarray.h @@ -105,6 +105,7 @@ public: typedef int difference_type; typedef QJsonValue value_type; typedef QJsonValueRef reference; + typedef QJsonValueRefPtr pointer; inline iterator() : a(0), i(0) { } explicit inline iterator(QJsonArray *array, int index) : a(array), i(index) { } @@ -149,6 +150,7 @@ public: typedef qptrdiff difference_type; typedef QJsonValue value_type; typedef QJsonValue reference; + typedef QJsonValuePtr pointer; inline const_iterator() : a(0), i(0) { } explicit inline const_iterator(const QJsonArray *array, int index) : a(array), i(index) { } From f3b93a7724929408a9b673674ffa73c164e0a771 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 12 Nov 2014 18:41:52 +0200 Subject: [PATCH 229/323] Android: Introduce getAccessibleField This method simplifies a lot the code. Change-Id: I7fe775d671ae89e112f313c21f61923133785785 Reviewed-by: J-P Nurmi --- .../qtproject/qt5/android/ExtractStyle.java | 73 +++++++------------ 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 2aeb89d5d5..cf05b674d2 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -96,7 +96,7 @@ public class ExtractStyle { native static int[] extractNativeChunkInfo20(long nativeChunk); - Class styleableClass = getStylableClass(); + Class styleableClass = getClass("android.R$styleable"); final int[] EMPTY_STATE_SET = {}; final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled}; final int[] FOCUSED_STATE_SET = {android.R.attr.state_focused}; @@ -387,15 +387,26 @@ public class ExtractStyle { return null; } - private Class getStylableClass() { + private Class getClass(String className) { try { - return Class.forName("android.R$styleable"); + return Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } + Field getAccessibleField(Class clazz, String fieldName) { + try { + Field f = clazz.getDeclaredField(fieldName); + f.setAccessible(true); + return f; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + int getField(Class clazz, String fieldName) { try { @@ -683,27 +694,13 @@ public class ExtractStyle { json.put("type", "rotate"); Object obj = drawable.getConstantState(); Class rotateStateClass = obj.getClass(); - Field f = rotateStateClass.getDeclaredField("mDrawable"); - f.setAccessible(true); - json.put("drawable", getDrawable(f.get(obj), filename, null)); - f = rotateStateClass.getDeclaredField("mPivotX"); - f.setAccessible(true); - json.put("pivotX", f.getFloat(obj)); - f = rotateStateClass.getDeclaredField("mPivotXRel"); - f.setAccessible(true); - json.put("pivotXRel", f.getBoolean(obj)); - f = rotateStateClass.getDeclaredField("mPivotY"); - f.setAccessible(true); - json.put("pivotY", f.getFloat(obj)); - f = rotateStateClass.getDeclaredField("mPivotYRel"); - f.setAccessible(true); - json.put("pivotYRel", f.getBoolean(obj)); - f = rotateStateClass.getDeclaredField("mFromDegrees"); - f.setAccessible(true); - json.put("fromDegrees", f.getFloat(obj)); - f = rotateStateClass.getDeclaredField("mToDegrees"); - f.setAccessible(true); - json.put("toDegrees", f.getFloat(obj)); + json.put("drawable", getDrawable(getAccessibleField(rotateStateClass, "mDrawable").get(obj), filename, null)); + json.put("pivotX", getAccessibleField(rotateStateClass, "mPivotX").getFloat(obj)); + json.put("pivotXRel", getAccessibleField(rotateStateClass, "mPivotXRel").getBoolean(obj)); + json.put("pivotY", getAccessibleField(rotateStateClass, "mPivotY").getFloat(obj)); + json.put("pivotYRel", getAccessibleField(rotateStateClass, "mPivotYRel").getBoolean(obj)); + json.put("fromDegrees", getAccessibleField(rotateStateClass, "mFromDegrees").getFloat(obj)); + json.put("toDegrees", getAccessibleField(rotateStateClass, "mToDegrees").getFloat(obj)); } catch (Exception e) { e.printStackTrace(); } @@ -774,22 +771,14 @@ public class ExtractStyle { private JSONObject findPatchesMarings(Drawable d) throws JSONException, NoSuchFieldException, IllegalAccessException { - Field mNinePatch = ((NinePatchDrawable)d).getClass().getDeclaredField("mNinePatch"); - mNinePatch.setAccessible(true); - NinePatch np = (NinePatch) mNinePatch.get(d); + NinePatch np = (NinePatch) getAccessibleField(NinePatchDrawable.class, "mNinePatch").get(d); if (Build.VERSION.SDK_INT < 19) - { - Field mChunk = np.getClass().getDeclaredField("mChunk"); - mChunk.setAccessible(true); - return getJsonChunkInfo(extractChunkInfo((byte[]) mChunk.get(np))); - } + return getJsonChunkInfo(extractChunkInfo((byte[]) getAccessibleField(np.getClass(), "mChunk").get(np))); else { - Field mNativeChunk = np.getClass().getDeclaredField("mNativeChunk"); - mNativeChunk.setAccessible(true); if (Build.VERSION.SDK_INT > 19) - return getJsonChunkInfo(extractNativeChunkInfo20(mNativeChunk.getLong(np))); - return getJsonChunkInfo(extractNativeChunkInfo(mNativeChunk.getInt(np))); + return getJsonChunkInfo(extractNativeChunkInfo20(getAccessibleField(np.getClass(), "mNativeChunk").getLong(np))); + return getJsonChunkInfo(extractNativeChunkInfo(getAccessibleField(np.getClass(), "mNativeChunk").getInt(np))); } } @@ -873,9 +862,7 @@ public class ExtractStyle { try { json.put("type", "clipDrawable"); Drawable.ConstantState dcs = ((ClipDrawable)drawable).getConstantState(); - Field f = dcs.getClass().getDeclaredField("mDrawable"); - f.setAccessible(true); - json.put("drawable", getDrawable(f.get(dcs), filename, null)); + json.put("drawable", getDrawable(getAccessibleField(dcs.getClass(), "mDrawable").get(dcs), filename, null)); if (null != padding) json.put("padding", getJsonRect(padding)); else { @@ -913,14 +900,10 @@ public class ExtractStyle { { try { InsetDrawable d = (InsetDrawable)drawable; - Field mInsetState = d.getClass().getDeclaredField("mInsetState"); - mInsetState.setAccessible(true); - Object mInsetStateObject = mInsetState.get(drawable); - Field mDrawable = mInsetStateObject.getClass().getDeclaredField("mDrawable"); - mDrawable.setAccessible(true); + Object mInsetStateObject = getAccessibleField(InsetDrawable.class, "mInsetState").get(d); Rect _padding = new Rect(); boolean hasPadding = d.getPadding(_padding); - return getDrawable(mDrawable.get(mInsetStateObject), filename, hasPadding ? _padding : null); + return getDrawable(getAccessibleField(mInsetStateObject.getClass(), "mDrawable").get(mInsetStateObject), filename, hasPadding ? _padding : null); } catch (Exception e) { e.printStackTrace(); } From f12d4ee3fb6e647a0407c058ca76847ed3854a5e Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Fri, 7 Nov 2014 23:52:20 +0100 Subject: [PATCH 230/323] iOS: close keyboard by resigning first responder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current approach of reloading input views assumes that the first responder is not a QIOSTextResponder, but a QUIView. This is not always the case, e.g if someone calls update after setting IM enabled on current focus object to false. In that case we'll try to close the keyboard by reloading input views on a quitextresponder which can fail if the text responder has an external input view attached. This patch will instead hide the keyboard by resigning first responder when it is a QIOSTextResponder. If it is not a QIOSTextResponder it means that the keyboard is already closed, or a third-party UIVIew that supports key input is first responder. In either case we then leave it as-is. Task-number: QTBUG-42523 Change-Id: I4dab648af9029941a8d5d3b00011fbd169be5482 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosinputcontext.h | 3 --- src/plugins/platforms/ios/qiosinputcontext.mm | 27 +++---------------- .../platforms/ios/qiostextresponder.mm | 15 ----------- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 1f1130f932..d2a9c261ba 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -85,15 +85,12 @@ public: const ImeState &imeState() { return m_imeState; }; bool inputMethodAccepted() const; - bool isReloadingInputViewsFromUpdate() const { return m_isReloadingInputViewsFromUpdate; } - static QIOSInputContext *instance(); private: QIOSKeyboardListener *m_keyboardListener; QIOSTextInputResponder *m_textResponder; ImeState m_imeState; - bool m_isReloadingInputViewsFromUpdate; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 072a49c7c5..e417e9a1fb 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -330,7 +330,6 @@ QIOSInputContext::QIOSInputContext() : QPlatformInputContext() , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_textResponder(0) - , m_isReloadingInputViewsFromUpdate(false) { if (isQtApplication()) connect(qGuiApp->inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QIOSInputContext::cursorRectangleChanged); @@ -540,10 +539,11 @@ void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) [m_textResponder autorelease]; m_textResponder = [[QIOSTextInputResponder alloc] initWithInputContext:this]; [m_textResponder becomeFirstResponder]; + } else if ([UIResponder currentFirstResponder] == m_textResponder) { + qImDebug() << "IM not enabled, resigning text responder as first responder"; + [m_textResponder resignFirstResponder]; } else { - qImDebug() << "IM not enabled, reloading input views"; - QScopedValueRollback recursionGuard(m_isReloadingInputViewsFromUpdate, true); - [[UIResponder currentFirstResponder] reloadInputViews]; + qImDebug() << "IM not enabled. Text responder not first responder. Nothing to do"; } } else { [m_textResponder notifyInputDelegate:changedProperties]; @@ -594,22 +594,3 @@ void QIOSInputContext::commit() [m_textResponder unmarkText]; [m_textResponder notifyInputDelegate:Qt::ImSurroundingText]; } - -// ------------------------------------------------------------------------- - -@interface QUIView (InputMethods) -- (void)reloadInputViews; -@end - -@implementation QUIView (InputMethods) -- (void)reloadInputViews -{ - if (QIOSInputContext::instance()->isReloadingInputViewsFromUpdate()) { - qImDebug() << "preventing recursion by reloading super"; - [super reloadInputViews]; - } else { - qImDebug() << "reseting input methods"; - qApp->inputMethod()->reset(); - } -} -@end diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 6bd1e711d0..2fcc7258f7 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -285,21 +285,6 @@ reinterpret_cast(qApp->focusWindow()->handle()->winId()) : 0; } -/*! - iOS uses [UIResponder(Internal) _requiresKeyboardWhenFirstResponder] to check if the - current responder should bring up the keyboard, which in turn checks if the responder - supports the UIKeyInput protocol. By dynamically reporting our protocol conformance - we can control the keyboard visibility depending on whether or not we have a focus - object with IME enabled. -*/ -- (BOOL)conformsToProtocol:(Protocol *)protocol -{ - if (protocol == @protocol(UIKeyInput)) - return m_inputContext->inputMethodAccepted(); - - return [super conformsToProtocol:protocol]; -} - // ------------------------------------------------------------------------- - (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties From bed25d8a3a27a439e5a50083be6b7218a8982d3c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 4 Nov 2014 14:08:33 +0100 Subject: [PATCH 231/323] iOS: let focusobject be ImEnabled when a menu is attached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the picker menu uses IM to set an alternative input view, we also need to specify that we IM is enabled. Task-number: QTBUG-42523 Change-Id: Ia559fbc0ca7e6a1a4499d5eb179baa2d915ecb17 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosmenu.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index 005b06547e..f64c1a2f41 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -452,11 +452,11 @@ void QIOSMenu::toggleShowUsingUIPickerView(bool show) Q_ASSERT(!focusObjectWithPickerView); focusObjectWithPickerView = qApp->focusWindow()->focusObject(); focusObjectWithPickerView->installEventFilter(this); - qApp->inputMethod()->update(Qt::ImPlatformData); + qApp->inputMethod()->update(Qt::ImEnabled | Qt::ImPlatformData); } else { Q_ASSERT(focusObjectWithPickerView); focusObjectWithPickerView->removeEventFilter(this); - qApp->inputMethod()->update(Qt::ImPlatformData); + qApp->inputMethod()->update(Qt::ImEnabled | Qt::ImPlatformData); focusObjectWithPickerView = 0; Q_ASSERT(m_pickerView); @@ -477,6 +477,7 @@ bool QIOSMenu::eventFilter(QObject *obj, QEvent *event) imPlatformData.insert(kImePlatformDataInputView, QVariant::fromValue(static_cast(m_pickerView))); imPlatformData.insert(kImePlatformDataInputAccessoryView, QVariant::fromValue(static_cast(m_pickerView.toolbar))); queryEvent->setValue(Qt::ImPlatformData, imPlatformData); + queryEvent->setValue(Qt::ImEnabled, true); return true; } From c506d938a83585d973cbc369e99503cf83db68e2 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 12 Nov 2014 12:28:16 +0100 Subject: [PATCH 232/323] iOS: close menu when keyboard hides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the menu is closed from the keyboard gesture, and the focus object doesn't change, the menu will still be in a visible state, even if the keyboard is hidden. This patch will ensure that this can not be the case by listening for keyboardWillHideNotification. Since we have no guarantee for when the destructor runs, we apply a pessimistic approach and ensure we stop listen when the menu gets closed. Task-number: QTBUG-42523 Change-Id: If734ea32d1823b978c9c1c67ebcc5b6c3c5c338c Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/ios/qiosmenu.mm | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index f64c1a2f41..0f351f785b 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -153,13 +153,29 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; [self setDelegate:self]; [self setDataSource:self]; [self selectRow:m_selectedRow inComponent:0 animated:false]; + [self listenForKeyboardWillHideNotification:YES]; } return self; } +-(void)listenForKeyboardWillHideNotification:(BOOL)listen +{ + if (listen) { + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(cancelMenu) + name:@"UIKeyboardWillHideNotification" object:nil]; + } else { + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIKeyboardWillHideNotification" object:nil]; + } +} + -(void)dealloc { + [self listenForKeyboardWillHideNotification:NO]; self.toolbar = 0; [super dealloc]; } @@ -193,6 +209,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (void)closeMenu { + [self listenForKeyboardWillHideNotification:NO]; if (!m_visibleMenuItems.isEmpty()) QIOSMenu::currentMenu()->handleItemSelected(m_visibleMenuItems.at(m_selectedRow)); else @@ -201,6 +218,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (void)cancelMenu { + [self listenForKeyboardWillHideNotification:NO]; QIOSMenu::currentMenu()->dismiss(); } From 74ae86a660abfbbdedfad1fe284a79af73fa4b78 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 12 Nov 2014 14:05:10 +0100 Subject: [PATCH 233/323] Doc: corrected autolink issue json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-40362 Change-Id: I851670eea6af80b0bb463f00b147d7a6ef289046 Reviewed-by: Martin Smith Reviewed-by: Topi Reiniö --- src/corelib/json/qjsonarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp index fd407af2cd..73c53ea649 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/json/qjsonarray.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE removing QJsonValue's from the array. A QJsonArray can be converted to and from a QVariantList. You can query the - number of entries with size(), insert(), and remove() entries from it + number of entries with size(), insert(), and removeAt() entries from it and iterate over its content using the standard C++ iterator pattern. QJsonArray is an implicitly shared class and shares the data with the document From 5c58db516a55d4f6a5e5899617505898ce7bd969 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 12 Nov 2014 13:55:25 +0100 Subject: [PATCH 234/323] Add the custom build step for PCH generated through source This fixes a regression introduced by 04d3a89e20d49a3b5015b071bfdedc81973b090c as it left out the custom build step for the source code file generated for PCH. Task-number: QTBUG-42596 Change-Id: I53d5a36b842dcffbde2657910e6a96dca0e99c7b Reviewed-by: Joerg Bornemann --- qmake/generators/win32/msbuild_objectmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 7effbaa8c4..1f51ff0342 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -1915,10 +1915,10 @@ bool VCXProjectWriter::outputFileConfig(OutputFilterData *d, XmlOutput &xml, Xml } // Actual XML output ---------------------------------- - if (hasCustomBuildStep || filter.useCompilerTool + if (hasCustomBuildStep || filter.useCustomBuildTool || filter.useCompilerTool || !d->inBuild || filter.Name.startsWith("Deployment Files")) { - if (hasCustomBuildStep) + if (hasCustomBuildStep || filter.useCustomBuildTool) { if (!fileAdded) { fileAdded = true; From 4fc1a100756ee86d96a320490ce747224ba9726a Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 12 Nov 2014 18:44:25 +0200 Subject: [PATCH 235/323] Android: Extract RippleDrawable Task-number: QTBUG-42488 Change-Id: I41fb37adae4664f4a071d794dc4a31a3ee3334aa Reviewed-by: J-P Nurmi --- .../qtproject/qt5/android/ExtractStyle.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index cf05b674d2..c65797a1de 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -95,8 +95,8 @@ public class ExtractStyle { native static int[] extractChunkInfo20(byte[] chunkData); native static int[] extractNativeChunkInfo20(long nativeChunk); - Class styleableClass = getClass("android.R$styleable"); + Class rippleDrawableClass = getClass("android.graphics.drawable.RippleDrawable"); final int[] EMPTY_STATE_SET = {}; final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled}; final int[] FOCUSED_STATE_SET = {android.R.attr.state_focused}; @@ -794,8 +794,27 @@ public class ExtractStyle { } private HashMap m_drawableCache = new HashMap(); + private JSONObject getRippleDrawable(Object drawable, String filename, Rect padding) + { + JSONObject json = getLayerDrawable(drawable, filename); + JSONObject ripple = new JSONObject(); + try { + final Object mState = getAccessibleField(rippleDrawableClass, "mState").get(drawable); + ripple.put("mask", getDrawable((Drawable)getAccessibleField(rippleDrawableClass, "mMask").get(drawable), filename, padding)); + ripple.put("maxRadius", getAccessibleField(mState.getClass(), "mMaxRadius").getInt(mState)); + ripple.put("color", getColorStateList((ColorStateList)getAccessibleField(mState.getClass(), "mColor").get(mState))); + json.put("ripple", ripple); + } catch (Exception e) { + e.printStackTrace(); + } + return json; + } + public JSONObject getDrawable(Object drawable, String filename, Rect padding) { + if (drawable == null) + return null; + DrawableCache dc = m_drawableCache.get(filename); if (dc != null) { @@ -833,6 +852,9 @@ public class ExtractStyle { } else { + + if (rippleDrawableClass != null && rippleDrawableClass.isInstance(drawable)) + return getRippleDrawable(drawable, filename, padding); if (drawable instanceof ScaleDrawable) { return getDrawable(((ScaleDrawable)drawable).getDrawable(), filename, null); From adf1b30934f2b2b92271955e7867a7b2620bc6b9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 10 Nov 2014 18:19:45 -0800 Subject: [PATCH 236/323] Make QVersionNumber private We're not ready. [ChangeLog][EDITORIAL] Remove all mentions of QVersionNumber. Change-Id: I03ad95992982eb3177f982c1eeddb6a6bc29336c Reviewed-by: Keith Gardner Reviewed-by: Lars Knoll --- src/corelib/tools/qversionnumber.cpp | 3 ++- src/corelib/tools/{qversionnumber.h => qversionnumber_p.h} | 0 src/testlib/qtest.h | 6 ------ src/testlib/qtestcase.cpp | 7 ------- tests/auto/corelib/tools/qversionnumber/qversionnumber.pro | 2 +- .../corelib/tools/qversionnumber/tst_qversionnumber.cpp | 2 +- 6 files changed, 4 insertions(+), 16 deletions(-) rename src/corelib/tools/{qversionnumber.h => qversionnumber_p.h} (100%) diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp index 4d148249c0..3c8a9db086 100644 --- a/src/corelib/tools/qversionnumber.cpp +++ b/src/corelib/tools/qversionnumber.cpp @@ -40,7 +40,7 @@ ** ****************************************************************************/ -#include +#include #include #include #include @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE /*! \class QVersionNumber \inmodule QtCore + \internal \since 5.4 \brief The QVersionNumber class contains a version number with an arbitrary number of segments. diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber_p.h similarity index 100% rename from src/corelib/tools/qversionnumber.h rename to src/corelib/tools/qversionnumber_p.h diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index d3443e7390..6298262958 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -164,11 +163,6 @@ template<> inline char *toString(const QVariant &v) return qstrdup(vstring.constData()); } -template<> inline char *toString(const QVersionNumber &version) -{ - return toString(version.toString()); -} - template<> inline bool qCompare(QString const &t1, QLatin1String const &t2, const char *actual, const char *expected, const char *file, int line) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 2d92b3f6bd..b174913eae 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1027,13 +1027,6 @@ QT_BEGIN_NAMESPACE Returns a textual representation of the given \a variant. */ -/*! - \fn char *QTest::toString(const QVersionNumber &version) - \overload - - Returns a textual representation of the given \a version. -*/ - /*! \fn void QTest::qWait(int ms) Waits for \a ms milliseconds. While waiting, events will be processed and diff --git a/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro b/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro index 08ee0dd3d9..1e74d42bbd 100644 --- a/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro +++ b/tests/auto/corelib/tools/qversionnumber/qversionnumber.pro @@ -1,4 +1,4 @@ CONFIG += testcase parallel_test TARGET = tst_qversionnumber -QT = core testlib +QT = core-private testlib SOURCES = tst_qversionnumber.cpp diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp index 18bc86620a..f97b8a4df8 100644 --- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp +++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp @@ -33,7 +33,7 @@ ****************************************************************************/ #include -#include +#include class tst_QVersionNumber : public QObject { From ca526496c3d5a1aef5d85c76b162adafe1b98627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Martins?= Date: Thu, 13 Nov 2014 16:08:36 +0000 Subject: [PATCH 237/323] Allow to use FT_Library_SetLcdFilter in bundled FreeType. For a default Qt build this change is a NOP, ftlcdfil.c is ifdefed by FT_CONFIG_OPTION_SUBPIXEL_RENDERING, which we don't define. But for users who changed ftoption.h, or are using 3rdparty/freetype/devel/ftoption.h instead of 3rdparty/freetype/include/freetype/config/ftoption.h they can now enable Subpixel rendering without getting a build error. Change-Id: I547e8a20514fcb97e4e56cb0100e9c2ed525f483 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Konstantin Ritt --- src/platformsupport/fontdatabases/basic/basic.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platformsupport/fontdatabases/basic/basic.pri b/src/platformsupport/fontdatabases/basic/basic.pri index 88be809cd8..c2b882ed5a 100644 --- a/src/platformsupport/fontdatabases/basic/basic.pri +++ b/src/platformsupport/fontdatabases/basic/basic.pri @@ -17,6 +17,7 @@ contains(QT_CONFIG, freetype) { $$QT_FREETYPE_DIR/src/base/ftbbox.c \ $$QT_FREETYPE_DIR/src/base/ftdebug.c \ $$QT_FREETYPE_DIR/src/base/ftglyph.c \ + $$QT_FREETYPE_DIR/src/base/ftlcdfil.c \ $$QT_FREETYPE_DIR/src/base/ftinit.c \ $$QT_FREETYPE_DIR/src/base/ftmm.c \ $$QT_FREETYPE_DIR/src/base/fttype1.c \ From c38f1f19b87d20f79394bca151268fc3cdcdd189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Thu, 13 Nov 2014 13:25:12 +0200 Subject: [PATCH 238/323] Blacklist one test function in tst_QNetworkReply Task-number: QTBUG-32435 Change-Id: I07b1888b33daa00864e1793c1d12b1dccf562664 Reviewed-by: Lars Knoll --- tests/auto/network/access/qnetworkreply/BLACKLIST | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index fbd72492d8..504396bdd1 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -7,3 +7,4 @@ osx [SslHandshakeFailedError] osx [httpAbort] +[backgroundRequestInterruption:ftp, bg, nobg] From c1081b9426596c55505838e6ff1318259749ec54 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 12 Nov 2014 14:11:51 +0100 Subject: [PATCH 239/323] QFusionStyle: properly indent an if statement Fix the style trap that leads people into thinking that's an else-if, while it's a plain if. Change-Id: I62963f0d6270eadcbd8aede7bac60f83968cb0d4 Reviewed-by: Friedemann Kleint --- src/widgets/styles/qfusionstyle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index c1d6d879a8..71a9b1abd7 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -553,7 +553,9 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem, arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor); } else if (header->sortIndicator & QStyleOptionHeader::SortDown) { arrow = colorizedImage(QLatin1String(":/qt-project.org/styles/commonstyle/images/fusion_arrow.png"), arrowColor, 180); - } if (!arrow.isNull()) { + } + + if (!arrow.isNull()) { r.setSize(QSize(arrow.width()/2, arrow.height()/2)); r.moveCenter(header->rect.center()); painter->drawPixmap(r.translated(offset), arrow); From 32db2f425a0b85bc03d7de42d7b44337d0aa16f4 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Fri, 14 Nov 2014 11:29:30 +0200 Subject: [PATCH 240/323] windows: fix platform compilation after ANGLE upgrade Upstream changed how WARP is meant to interact with EGL, and so the enum names changed. Change-Id: I10d4bcac71b75a1223ea8af4d3fcf584f5685a02 Reviewed-by: Kai Koehne Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowseglcontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 3b277c0b5a..c0d0c1f77c 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -360,10 +360,10 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create() EGLDisplay display = EGL_NO_DISPLAY; #ifdef EGL_ANGLE_platform_angle_opengl if (libEGL.eglGetPlatformDisplayEXT && qEnvironmentVariableIsSet("QT_ANGLE_PLATFORM")) { - const EGLint anglePlatformAttributes[][3] = { + const EGLint anglePlatformAttributes[][5] = { { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE }, { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_NONE }, - { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE, EGL_NONE } + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE, EGL_NONE } }; const EGLint *attributes = 0; const QByteArray anglePlatform = qgetenv("QT_ANGLE_PLATFORM"); From c6df5fe3ed0f2a722931be098914978cf17a666f Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Fri, 14 Nov 2014 10:52:01 +0200 Subject: [PATCH 241/323] ANGLE: Upgrade to version 1.2.30d6c255d238 The following patches have been changed: 0001-Fix-compilation-for-MSVC-2008-and-std-tuple.patch Removed because it is no longer possible to build ANGLE with MSVC2008 0002-Fix-compilation-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch Removed because the minimum version of MinGW moved to 4.8.2 0005-Fix-build-when-SSE2-is-not-available.patch Removed because it was fixed upstream 0006-Fix-compilation-of-libGLESv2-with-older-MinGW-w64-he.patch Removed because older versions of MinGW are not supported 0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch Removed because it was fixed upstream Task-number: QTBUG-41903 Change-Id: I976d30802f7f6fee725cf9a9f1325d5e82609835 Reviewed-by: Friedemann Kleint Reviewed-by: Kai Koehne Reviewed-by: Oliver Wolff --- src/3rdparty/angle/AUTHORS | 2 + src/3rdparty/angle/CONTRIBUTORS | 5 + src/3rdparty/angle/include/EGL/egl.h | 2 +- src/3rdparty/angle/include/EGL/eglext.h | 16 +- src/3rdparty/angle/include/EGL/eglplatform.h | 19 +- .../angle/include/GLSLANG/ShaderLang.h | 210 +- .../angle/include/GLSLANG/ShaderVars.h | 64 +- .../angle/include/angle_windowsstore.h | 37 + src/3rdparty/angle/src/commit.h | 4 +- src/3rdparty/angle/src/common/NativeWindow.h | 77 + src/3rdparty/angle/src/common/angleutils.cpp | 35 +- src/3rdparty/angle/src/common/angleutils.h | 11 + src/3rdparty/angle/src/common/debug.cpp | 246 +- src/3rdparty/angle/src/common/debug.h | 19 +- src/3rdparty/angle/src/common/features.h | 35 + src/3rdparty/angle/src/common/mathutil.h | 4 +- src/3rdparty/angle/src/common/platform.h | 89 +- src/3rdparty/angle/src/common/tls.cpp | 107 +- src/3rdparty/angle/src/common/tls.h | 17 +- src/3rdparty/angle/src/common/utilities.cpp | 89 +- src/3rdparty/angle/src/common/utilities.h | 6 + .../angle/src/common/win32/NativeWindow.cpp | 66 + .../common/winrt/CoreWindowNativeWindow.cpp | 200 ++ .../src/common/winrt/CoreWindowNativeWindow.h | 39 + .../common/winrt/InspectableNativeWindow.cpp | 274 +++ .../common/winrt/InspectableNativeWindow.h | 91 + .../winrt/SwapChainPanelNativeWindow.cpp | 226 ++ .../common/winrt/SwapChainPanelNativeWindow.h | 79 + .../preprocessor/DirectiveHandlerBase.h | 3 +- .../compiler/preprocessor/DirectiveParser.cpp | 35 +- .../compiler/preprocessor/MacroExpander.cpp | 4 +- .../src/compiler/translator/Compiler.cpp | 63 +- .../angle/src/compiler/translator/Compiler.h | 10 +- .../translator/DetectDiscontinuity.cpp | 52 + .../compiler/translator/DetectDiscontinuity.h | 19 + .../compiler/translator/DirectiveHandler.cpp | 79 +- .../compiler/translator/DirectiveHandler.h | 3 +- .../src/compiler/translator/IntermNode.cpp | 76 + .../src/compiler/translator/IntermNode.h | 5 + .../src/compiler/translator/Intermediate.cpp | 1 + .../compiler/translator/OutputGLSLBase.cpp | 18 +- .../src/compiler/translator/OutputHLSL.cpp | 59 +- .../src/compiler/translator/OutputHLSL.h | 1 + .../src/compiler/translator/ParseContext.cpp | 13 +- .../src/compiler/translator/ParseContext.h | 2 +- .../angle/src/compiler/translator/Pragma.h | 12 +- .../src/compiler/translator/ShaderLang.cpp | 371 +-- .../src/compiler/translator/ShaderVars.cpp | 165 ++ .../src/compiler/translator/SymbolTable.h | 41 +- .../compiler/translator/TranslatorESSL.cpp | 11 +- .../compiler/translator/TranslatorGLSL.cpp | 30 +- .../src/compiler/translator/TranslatorGLSL.h | 12 +- .../translator/ValidateLimitations.cpp | 1 + .../src/compiler/translator/VariableInfo.cpp | 81 +- .../src/compiler/translator/VariableInfo.h | 17 +- .../src/compiler/translator/VersionGLSL.cpp | 16 +- .../src/compiler/translator/VersionGLSL.h | 4 +- .../angle/src/compiler/translator/glslang.y | 34 +- .../src/compiler/translator/intermOut.cpp | 6 +- .../angle/src/compiler/translator/util.cpp | 47 +- .../angle/src/compiler/translator/util.h | 12 +- .../angle/src/libEGL/AttributeMap.cpp | 40 + src/3rdparty/angle/src/libEGL/AttributeMap.h | 33 + src/3rdparty/angle/src/libEGL/Display.cpp | 171 +- src/3rdparty/angle/src/libEGL/Display.h | 22 +- src/3rdparty/angle/src/libEGL/Error.cpp | 48 + src/3rdparty/angle/src/libEGL/Error.h | 39 + src/3rdparty/angle/src/libEGL/Surface.cpp | 341 +-- src/3rdparty/angle/src/libEGL/Surface.h | 60 +- src/3rdparty/angle/src/libEGL/libEGL.cpp | 469 ++-- src/3rdparty/angle/src/libEGL/main.cpp | 40 +- src/3rdparty/angle/src/libEGL/main.h | 22 +- .../angle/src/libGLESv2/BinaryStream.h | 12 +- src/3rdparty/angle/src/libGLESv2/Buffer.h | 1 - src/3rdparty/angle/src/libGLESv2/Context.cpp | 865 +------ src/3rdparty/angle/src/libGLESv2/Context.h | 62 +- src/3rdparty/angle/src/libGLESv2/Data.cpp | 51 + src/3rdparty/angle/src/libGLESv2/Data.h | 38 + src/3rdparty/angle/src/libGLESv2/Fence.cpp | 176 +- src/3rdparty/angle/src/libGLESv2/Fence.h | 35 +- .../angle/src/libGLESv2/Framebuffer.cpp | 277 +-- .../angle/src/libGLESv2/Framebuffer.h | 50 +- .../src/libGLESv2/FramebufferAttachment.cpp | 2 +- .../src/libGLESv2/FramebufferAttachment.h | 7 - .../angle/src/libGLESv2/ImageIndex.cpp | 91 + src/3rdparty/angle/src/libGLESv2/ImageIndex.h | 29 +- src/3rdparty/angle/src/libGLESv2/Program.cpp | 24 +- src/3rdparty/angle/src/libGLESv2/Program.h | 5 +- .../angle/src/libGLESv2/ProgramBinary.cpp | 2098 ++--------------- .../angle/src/libGLESv2/ProgramBinary.h | 133 +- .../angle/src/libGLESv2/Renderbuffer.cpp | 235 +- .../angle/src/libGLESv2/Renderbuffer.h | 113 +- .../angle/src/libGLESv2/ResourceManager.cpp | 16 +- .../angle/src/libGLESv2/ResourceManager.h | 7 +- src/3rdparty/angle/src/libGLESv2/Shader.cpp | 10 +- src/3rdparty/angle/src/libGLESv2/Shader.h | 4 +- src/3rdparty/angle/src/libGLESv2/State.cpp | 125 +- src/3rdparty/angle/src/libGLESv2/State.h | 26 +- src/3rdparty/angle/src/libGLESv2/Texture.cpp | 199 +- src/3rdparty/angle/src/libGLESv2/Texture.h | 74 +- .../angle/src/libGLESv2/VertexArray.h | 5 +- .../angle/src/libGLESv2/angletypes.cpp | 21 +- src/3rdparty/angle/src/libGLESv2/angletypes.h | 16 +- .../angle/src/libGLESv2/libGLESv2.cpp | 1045 ++++---- src/3rdparty/angle/src/libGLESv2/main.cpp | 101 +- src/3rdparty/angle/src/libGLESv2/main.h | 21 +- .../angle/src/libGLESv2/renderer/BufferImpl.h | 3 +- .../angle/src/libGLESv2/renderer/FenceImpl.h | 36 +- .../angle/src/libGLESv2/renderer/Image.cpp | 22 +- .../angle/src/libGLESv2/renderer/Image.h | 25 +- .../libGLESv2/renderer/IndexRangeCache.cpp | 4 - .../src/libGLESv2/renderer/ProgramImpl.cpp | 146 ++ .../src/libGLESv2/renderer/ProgramImpl.h | 119 +- .../src/libGLESv2/renderer/RenderTarget.cpp | 36 + .../src/libGLESv2/renderer/RenderTarget.h | 41 +- .../libGLESv2/renderer/RenderbufferImpl.cpp | 21 + .../src/libGLESv2/renderer/RenderbufferImpl.h | 41 + .../angle/src/libGLESv2/renderer/Renderer.cpp | 47 +- .../angle/src/libGLESv2/renderer/Renderer.h | 307 +-- .../src/libGLESv2/renderer/ShaderExecutable.h | 13 +- .../angle/src/libGLESv2/renderer/ShaderImpl.h | 3 +- .../angle/src/libGLESv2/renderer/SwapChain.h | 25 +- .../src/libGLESv2/renderer/TextureImpl.h | 24 +- .../src/libGLESv2/renderer/Workarounds.h | 39 + .../src/libGLESv2/renderer/copyimage.cpp | 2 +- .../src/libGLESv2/renderer/d3d/BufferD3D.cpp | 12 +- .../src/libGLESv2/renderer/d3d/BufferD3D.h | 17 +- .../libGLESv2/renderer/d3d/DynamicHLSL.cpp | 68 +- .../src/libGLESv2/renderer/d3d/DynamicHLSL.h | 35 +- .../libGLESv2/renderer/d3d/HLSLCompiler.cpp | 255 +- .../src/libGLESv2/renderer/d3d/HLSLCompiler.h | 28 +- .../src/libGLESv2/renderer/d3d/ImageD3D.cpp | 4 +- .../src/libGLESv2/renderer/d3d/ImageD3D.h | 15 +- .../libGLESv2/renderer/d3d/IndexBuffer.cpp | 8 +- .../src/libGLESv2/renderer/d3d/IndexBuffer.h | 10 +- .../renderer/d3d/IndexDataManager.cpp | 24 +- .../libGLESv2/renderer/d3d/IndexDataManager.h | 6 +- .../src/libGLESv2/renderer/d3d/ProgramD3D.cpp | 1814 +++++++++++++- .../src/libGLESv2/renderer/d3d/ProgramD3D.h | 180 +- .../renderer/d3d/RenderbufferD3D.cpp | 108 + .../libGLESv2/renderer/d3d/RenderbufferD3D.h | 51 + .../libGLESv2/renderer/d3d/RendererD3D.cpp | 796 +++++++ .../src/libGLESv2/renderer/d3d/RendererD3D.h | 195 ++ .../src/libGLESv2/renderer/d3d/ShaderD3D.cpp | 118 +- .../src/libGLESv2/renderer/d3d/ShaderD3D.h | 22 +- .../src/libGLESv2/renderer/d3d/TextureD3D.cpp | 1723 +++++++++----- .../src/libGLESv2/renderer/d3d/TextureD3D.h | 227 +- .../libGLESv2/renderer/d3d/TextureStorage.cpp | 18 +- .../libGLESv2/renderer/d3d/TextureStorage.h | 21 +- .../libGLESv2/renderer/d3d/VertexBuffer.cpp | 12 +- .../src/libGLESv2/renderer/d3d/VertexBuffer.h | 10 +- .../renderer/d3d/VertexDataManager.cpp | 36 +- .../renderer/d3d/VertexDataManager.h | 13 +- .../libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 110 +- .../src/libGLESv2/renderer/d3d/d3d11/Blit11.h | 38 +- .../libGLESv2/renderer/d3d/d3d11/Buffer11.cpp | 88 +- .../libGLESv2/renderer/d3d/d3d11/Buffer11.h | 8 +- .../libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 19 +- .../libGLESv2/renderer/d3d/d3d11/Clear11.h | 2 +- .../libGLESv2/renderer/d3d/d3d11/Fence11.cpp | 220 +- .../libGLESv2/renderer/d3d/d3d11/Fence11.h | 48 +- .../libGLESv2/renderer/d3d/d3d11/Image11.cpp | 563 +++-- .../libGLESv2/renderer/d3d/d3d11/Image11.h | 40 +- .../renderer/d3d/d3d11/IndexBuffer11.h | 2 +- .../renderer/d3d/d3d11/InputLayoutCache.cpp | 14 +- .../renderer/d3d/d3d11/PixelTransfer11.cpp | 126 +- .../renderer/d3d/d3d11/PixelTransfer11.h | 12 +- .../libGLESv2/renderer/d3d/d3d11/Query11.cpp | 3 +- .../libGLESv2/renderer/d3d/d3d11/Query11.h | 4 +- .../renderer/d3d/d3d11/RenderStateCache.cpp | 15 +- .../renderer/d3d/d3d11/RenderStateCache.h | 3 +- .../renderer/d3d/d3d11/RenderTarget11.cpp | 439 ++-- .../renderer/d3d/d3d11/RenderTarget11.h | 84 +- .../renderer/d3d/d3d11/Renderer11.cpp | 1388 ++++++----- .../libGLESv2/renderer/d3d/d3d11/Renderer11.h | 160 +- .../renderer/d3d/d3d11/SwapChain11.cpp | 169 +- .../renderer/d3d/d3d11/SwapChain11.h | 10 +- .../renderer/d3d/d3d11/TextureStorage11.cpp | 1935 ++++++++------- .../renderer/d3d/d3d11/TextureStorage11.h | 187 +- .../renderer/d3d/d3d11/VertexArray11.h | 4 +- .../renderer/d3d/d3d11/VertexBuffer11.cpp | 13 +- .../renderer/d3d/d3d11/VertexBuffer11.h | 4 +- .../renderer/d3d/d3d11/formatutils11.cpp | 2 +- .../renderer/d3d/d3d11/renderer11_utils.cpp | 94 +- .../renderer/d3d/d3d11/renderer11_utils.h | 6 +- .../src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp | 231 +- .../src/libGLESv2/renderer/d3d/d3d9/Blit9.h | 32 +- .../libGLESv2/renderer/d3d/d3d9/Buffer9.cpp | 13 +- .../src/libGLESv2/renderer/d3d/d3d9/Buffer9.h | 8 +- .../libGLESv2/renderer/d3d/d3d9/Fence9.cpp | 63 +- .../src/libGLESv2/renderer/d3d/d3d9/Fence9.h | 19 +- .../libGLESv2/renderer/d3d/d3d9/Image9.cpp | 706 +++--- .../src/libGLESv2/renderer/d3d/d3d9/Image9.h | 43 +- .../renderer/d3d/d3d9/IndexBuffer9.h | 2 +- .../libGLESv2/renderer/d3d/d3d9/Query9.cpp | 2 +- .../src/libGLESv2/renderer/d3d/d3d9/Query9.h | 4 +- .../renderer/d3d/d3d9/RenderTarget9.cpp | 177 +- .../renderer/d3d/d3d9/RenderTarget9.h | 60 +- .../libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 790 ++++--- .../libGLESv2/renderer/d3d/d3d9/Renderer9.h | 134 +- .../libGLESv2/renderer/d3d/d3d9/ShaderCache.h | 12 +- .../renderer/d3d/d3d9/SwapChain9.cpp | 26 +- .../libGLESv2/renderer/d3d/d3d9/SwapChain9.h | 7 +- .../renderer/d3d/d3d9/TextureStorage9.cpp | 431 ++-- .../renderer/d3d/d3d9/TextureStorage9.h | 46 +- .../renderer/d3d/d3d9/VertexArray9.h | 4 +- .../renderer/d3d/d3d9/VertexBuffer9.cpp | 16 +- .../renderer/d3d/d3d9/VertexBuffer9.h | 4 +- .../renderer/d3d/d3d9/renderer9_utils.cpp | 28 +- .../renderer/d3d/d3d9/renderer9_utils.h | 5 +- .../src/libGLESv2/renderer/loadimageSSE2.cpp | 18 +- .../angle/src/libGLESv2/validationES.cpp | 66 +- .../angle/src/libGLESv2/validationES3.cpp | 23 +- .../src/third_party/systeminfo/SystemInfo.cpp | 5 + .../0000-General-fixes-for-ANGLE-2.1.patch | 1192 +--------- ...pilation-for-MSVC-2008-and-std-tuple.patch | 31 - ...-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch | 33 - ...-to-link-ANGLE-statically-for-single.patch | 31 +- ...Fix-build-when-SSE2-is-not-available.patch | 84 - ...of-libGLESv2-with-older-MinGW-w64-he.patch | 49 - ...-with-Microsoft-Visual-Studio-14-CTP.patch | 28 - ...y-load-D3D-compiler-from-a-list-or-t.patch | 37 +- .../patches/0009-ANGLE-Support-WinRT.patch | 1921 ++++++--------- ...able-D3D11-for-feature-level-9-cards.patch | 268 ++- ...0012-ANGLE-fix-semantic-index-lookup.patch | 16 +- ...support-for-querying-platform-device.patch | 31 +- ...e-multithreaded-devices-if-necessary.patch | 37 +- ...15-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch | 309 ++- ...GLE-Fix-compilation-with-MinGW-D3D11.patch | 322 +-- src/angle/src/libEGL/libEGL.pro | 20 + src/angle/src/libGLESv2/libGLESv2.pro | 26 +- 231 files changed, 16959 insertions(+), 13672 deletions(-) create mode 100644 src/3rdparty/angle/include/angle_windowsstore.h create mode 100644 src/3rdparty/angle/src/common/NativeWindow.h create mode 100644 src/3rdparty/angle/src/common/features.h create mode 100644 src/3rdparty/angle/src/common/win32/NativeWindow.cpp create mode 100644 src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h create mode 100644 src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h create mode 100644 src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp create mode 100644 src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h create mode 100644 src/3rdparty/angle/src/libEGL/AttributeMap.cpp create mode 100644 src/3rdparty/angle/src/libEGL/AttributeMap.h create mode 100644 src/3rdparty/angle/src/libEGL/Error.cpp create mode 100644 src/3rdparty/angle/src/libEGL/Error.h create mode 100644 src/3rdparty/angle/src/libGLESv2/Data.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/Data.h create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp create mode 100644 src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h delete mode 100644 src/angle/patches/0001-Fix-compilation-for-MSVC-2008-and-std-tuple.patch delete mode 100644 src/angle/patches/0002-Fix-compilation-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch delete mode 100644 src/angle/patches/0005-Fix-build-when-SSE2-is-not-available.patch delete mode 100644 src/angle/patches/0006-Fix-compilation-of-libGLESv2-with-older-MinGW-w64-he.patch delete mode 100644 src/angle/patches/0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch diff --git a/src/3rdparty/angle/AUTHORS b/src/3rdparty/angle/AUTHORS index b79bb5d161..be114bcf68 100644 --- a/src/3rdparty/angle/AUTHORS +++ b/src/3rdparty/angle/AUTHORS @@ -21,10 +21,12 @@ Mozilla Corporation Turbulenz Klarälvdalens Datakonsult AB Microsoft Open Technologies, Inc. +NVIDIA Corporation Jacek Caban Mark Callow Ginn Chen +Tibor den Ouden James Hauxwell Sam Hocevar Pierre Leveille diff --git a/src/3rdparty/angle/CONTRIBUTORS b/src/3rdparty/angle/CONTRIBUTORS index 0cae10a0f6..94d009f2b3 100644 --- a/src/3rdparty/angle/CONTRIBUTORS +++ b/src/3rdparty/angle/CONTRIBUTORS @@ -78,7 +78,12 @@ Turbulenz Ulrik Persson (ddefrostt) Mark Banner (standard8mbp) David Kilzer +Jacek Caban +Tibor den Ouden Microsoft Open Technologies, Inc. Cooper Partin Austin Kinross + +NVIDIA Corporation + Olli Etuaho diff --git a/src/3rdparty/angle/include/EGL/egl.h b/src/3rdparty/angle/include/EGL/egl.h index ab2f0cdfbe..12590a0e20 100644 --- a/src/3rdparty/angle/include/EGL/egl.h +++ b/src/3rdparty/angle/include/EGL/egl.h @@ -238,7 +238,7 @@ EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void); #ifndef EGL_VERSION_1_5 #define EGL_VERSION_1_5 1 typedef void *EGLSync; -typedef khronos_intptr_t EGLAttrib; +typedef intptr_t EGLAttrib; typedef khronos_utime_nanoseconds_t EGLTime; #define EGL_CONTEXT_MAJOR_VERSION 0x3098 #define EGL_CONTEXT_MINOR_VERSION 0x30FB diff --git a/src/3rdparty/angle/include/EGL/eglext.h b/src/3rdparty/angle/include/EGL/eglext.h index 989359b026..0cc5eec293 100644 --- a/src/3rdparty/angle/include/EGL/eglext.h +++ b/src/3rdparty/angle/include/EGL/eglext.h @@ -59,7 +59,7 @@ extern "C" { #ifndef EGL_KHR_cl_event2 #define EGL_KHR_cl_event2 1 typedef void *EGLSyncKHR; -typedef khronos_intptr_t EGLAttribKHR; +typedef intptr_t EGLAttribKHR; typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list); #ifdef EGL_EGLEXT_PROTOTYPES EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list); @@ -442,20 +442,22 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSu #define EGL_ANGLE_platform_angle 1 #define EGL_PLATFORM_ANGLE_ANGLE 0x3201 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3204 +#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3205 #endif /* EGL_ANGLE_platform_angle */ #ifndef EGL_ANGLE_platform_angle_d3d #define EGL_ANGLE_platform_angle_d3d 1 -#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3204 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3205 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206 +#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3206 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207 +#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208 #endif /* EGL_ANGLE_platform_angle_d3d */ #ifndef EGL_ANGLE_platform_angle_opengl #define EGL_ANGLE_platform_angle_opengl 1 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3207 -#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3209 +#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320A #endif /* EGL_ANGLE_platform_angle_opengl */ #ifndef EGL_ARM_pixmap_multisample_discard diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h index ea9f5778ee..2eb3674a0b 100644 --- a/src/3rdparty/angle/include/EGL/eglplatform.h +++ b/src/3rdparty/angle/include/EGL/eglplatform.h @@ -67,23 +67,22 @@ * implementations. */ -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) /* Windows Runtime */ - -struct IUnknown; - -typedef IUnknown *EGLNativeDisplayType; -typedef void *EGLNativePixmapType; -typedef IUnknown *EGLNativeWindowType; - -#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif #include -typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; + +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */ +#include +typedef IInspectable* EGLNativeDisplayType; +typedef IInspectable* EGLNativeWindowType; +#else +typedef HDC EGLNativeDisplayType; typedef HWND EGLNativeWindowType; +#endif #elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h index b7989f5f7e..647fed6a02 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderLang.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderLang.h @@ -27,6 +27,10 @@ #include "KHR/khrplatform.h" +#include +#include +#include + // // This is the platform independent interface between an OGL driver // and the shading language compiler. @@ -42,18 +46,17 @@ typedef unsigned int GLenum; // Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h #include "ShaderVars.h" -#ifdef __cplusplus -extern "C" { -#endif - // Version number for shader translation API. // It is incremented every time the API changes. -#define ANGLE_SH_VERSION 130 +#define ANGLE_SH_VERSION 132 typedef enum { SH_GLES2_SPEC = 0x8B40, SH_WEBGL_SPEC = 0x8B41, + SH_GLES3_SPEC = 0x8B86, + SH_WEBGL2_SPEC = 0x8B87, + // The CSS Shaders spec is a subset of the WebGL spec. // // In both CSS vertex and fragment shaders, ANGLE: @@ -85,31 +88,6 @@ typedef enum { SH_HLSL11_OUTPUT = 0x8B48 } ShShaderOutput; -typedef enum { - SH_PRECISION_HIGHP = 0x5001, - SH_PRECISION_MEDIUMP = 0x5002, - SH_PRECISION_LOWP = 0x5003, - SH_PRECISION_UNDEFINED = 0 -} ShPrecisionType; - -typedef enum { - SH_INFO_LOG_LENGTH = 0x8B84, - SH_OBJECT_CODE_LENGTH = 0x8B88, // GL_SHADER_SOURCE_LENGTH - SH_ACTIVE_UNIFORMS = 0x8B86, - SH_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87, - SH_ACTIVE_ATTRIBUTES = 0x8B89, - SH_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A, - SH_VARYINGS = 0x8BBB, - SH_VARYING_MAX_LENGTH = 0x8BBC, - SH_MAPPED_NAME_MAX_LENGTH = 0x6000, - SH_NAME_MAX_LENGTH = 0x6001, - SH_HASHED_NAME_MAX_LENGTH = 0x6002, - SH_HASHED_NAMES_COUNT = 0x6003, - SH_SHADER_VERSION = 0x6004, - SH_RESOURCES_STRING_LENGTH = 0x6005, - SH_OUTPUT_TYPE = 0x6006 -} ShShaderInfo; - // Compile options. typedef enum { SH_VALIDATE = 0, @@ -208,14 +186,14 @@ typedef enum { // // Driver must call this first, once, before doing any other // compiler operations. -// If the function succeeds, the return value is nonzero, else zero. +// If the function succeeds, the return value is true, else false. // -COMPILER_EXPORT int ShInitialize(); +COMPILER_EXPORT bool ShInitialize(); // // Driver should call this at shutdown. -// If the function succeeds, the return value is nonzero, else zero. +// If the function succeeds, the return value is true, else false. // -COMPILER_EXPORT int ShFinalize(); +COMPILER_EXPORT bool ShFinalize(); // The 64 bits hash function. The first parameter is the input string; the // second parameter is the string length. @@ -246,6 +224,12 @@ typedef struct int EXT_frag_depth; int EXT_shader_texture_lod; + // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives + // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate + // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers + // function. This applies to Tegra K1 devices. + int NV_draw_buffers; + // Set to 1 if highp precision is supported in the fragment language. // Default is 0. int FragmentPrecisionHigh; @@ -274,8 +258,10 @@ typedef struct // // Initialize built-in resources with minimum expected values. +// Parameters: +// resources: The object to initialize. Will be comparable with memcmp. // -COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources); +COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources); // // ShHandle held by but opaque to the driver. It is allocated, @@ -284,18 +270,15 @@ COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources* resources); // // If handle creation fails, 0 will be returned. // -typedef void* ShHandle; +typedef void *ShHandle; // -// Returns the a concatenated list of the items in ShBuiltInResources as a string. +// Returns the a concatenated list of the items in ShBuiltInResources as a +// null-terminated string. // This function must be updated whenever ShBuiltInResources is changed. // Parameters: // handle: Specifies the handle of the compiler to be used. -// outStringLen: Specifies the size of the buffer, in number of characters. The size -// of the buffer required to store the resources string can be obtained -// by calling ShGetInfo with SH_RESOURCES_STRING_LENGTH. -// outStr: Returns a null-terminated string representing all the built-in resources. -COMPILER_EXPORT void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outStr); +COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle handle); // // Driver calls these to create and destroy compiler objects. @@ -313,12 +296,12 @@ COMPILER_EXPORT ShHandle ShConstructCompiler( sh::GLenum type, ShShaderSpec spec, ShShaderOutput output, - const ShBuiltInResources* resources); + const ShBuiltInResources *resources); COMPILER_EXPORT void ShDestruct(ShHandle handle); // // Compiles the given shader source. -// If the function succeeds, the return value is nonzero, else zero. +// If the function succeeds, the return value is true, else false. // Parameters: // handle: Specifies the handle of compiler to be used. // shaderStrings: Specifies an array of pointers to null-terminated strings @@ -340,123 +323,36 @@ COMPILER_EXPORT void ShDestruct(ShHandle handle); // SH_VARIABLES: Extracts attributes, uniforms, and varyings. // Can be queried by calling ShGetVariableInfo(). // -COMPILER_EXPORT int ShCompile( +COMPILER_EXPORT bool ShCompile( const ShHandle handle, - const char* const shaderStrings[], + const char * const shaderStrings[], size_t numStrings, - int compileOptions - ); + int compileOptions); -// Returns a parameter from a compiled shader. +// Return the version of the shader language. +COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle); + +// Return the currently set language output type. +COMPILER_EXPORT ShShaderOutput ShGetShaderOutputType( + const ShHandle handle); + +// Returns null-terminated information log for a compiled shader. // Parameters: // handle: Specifies the compiler -// pname: Specifies the parameter to query. -// The following parameters are defined: -// SH_INFO_LOG_LENGTH: the number of characters in the information log -// including the null termination character. -// SH_OBJECT_CODE_LENGTH: the number of characters in the object code -// including the null termination character. -// SH_ACTIVE_ATTRIBUTES: the number of active attribute variables. -// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: the length of the longest active attribute -// variable name including the null -// termination character. -// SH_ACTIVE_UNIFORMS: the number of active uniform variables. -// SH_ACTIVE_UNIFORM_MAX_LENGTH: the length of the longest active uniform -// variable name including the null -// termination character. -// SH_VARYINGS: the number of varying variables. -// SH_VARYING_MAX_LENGTH: the length of the longest varying variable name -// including the null termination character. -// SH_MAPPED_NAME_MAX_LENGTH: the length of the mapped variable name including -// the null termination character. -// SH_NAME_MAX_LENGTH: the max length of a user-defined name including the -// null termination character. -// SH_HASHED_NAME_MAX_LENGTH: the max length of a hashed name including the -// null termination character. -// SH_HASHED_NAMES_COUNT: the number of hashed names from the latest compile. -// SH_SHADER_VERSION: the version of the shader language -// SH_OUTPUT_TYPE: the currently set language output type -// -// params: Requested parameter -COMPILER_EXPORT void ShGetInfo(const ShHandle handle, - ShShaderInfo pname, - size_t* params); - -// Returns nul-terminated information log for a compiled shader. -// Parameters: -// handle: Specifies the compiler -// infoLog: Specifies an array of characters that is used to return -// the information log. It is assumed that infoLog has enough memory -// to accomodate the information log. The size of the buffer required -// to store the returned information log can be obtained by calling -// ShGetInfo with SH_INFO_LOG_LENGTH. -COMPILER_EXPORT void ShGetInfoLog(const ShHandle handle, char* infoLog); +COMPILER_EXPORT const std::string &ShGetInfoLog(const ShHandle handle); // Returns null-terminated object code for a compiled shader. // Parameters: // handle: Specifies the compiler -// infoLog: Specifies an array of characters that is used to return -// the object code. It is assumed that infoLog has enough memory to -// accomodate the object code. The size of the buffer required to -// store the returned object code can be obtained by calling -// ShGetInfo with SH_OBJECT_CODE_LENGTH. -COMPILER_EXPORT void ShGetObjectCode(const ShHandle handle, char* objCode); +COMPILER_EXPORT const std::string &ShGetObjectCode(const ShHandle handle); -// Returns information about a shader variable. +// Returns a (original_name, hash) map containing all the user defined +// names in the shader, including variable names, function names, struct +// names, and struct field names. // Parameters: // handle: Specifies the compiler -// variableType: Specifies the variable type; options include -// SH_ACTIVE_ATTRIBUTES, SH_ACTIVE_UNIFORMS, SH_VARYINGS. -// index: Specifies the index of the variable to be queried. -// length: Returns the number of characters actually written in the string -// indicated by name (excluding the null terminator) if a value other -// than NULL is passed. -// size: Returns the size of the variable. -// type: Returns the data type of the variable. -// precision: Returns the precision of the variable. -// staticUse: Returns 1 if the variable is accessed in a statement after -// pre-processing, whether or not run-time flow of control will -// cause that statement to be executed. -// Returns 0 otherwise. -// name: Returns a null terminated string containing the name of the -// variable. It is assumed that name has enough memory to accormodate -// the variable name. The size of the buffer required to store the -// variable name can be obtained by calling ShGetInfo with -// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_ACTIVE_UNIFORM_MAX_LENGTH, -// SH_VARYING_MAX_LENGTH. -// mappedName: Returns a null terminated string containing the mapped name of -// the variable, It is assumed that mappedName has enough memory -// (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care about the -// mapped name. If the name is not mapped, then name and mappedName -// are the same. -COMPILER_EXPORT void ShGetVariableInfo(const ShHandle handle, - ShShaderInfo variableType, - int index, - size_t* length, - int* size, - sh::GLenum* type, - ShPrecisionType* precision, - int* staticUse, - char* name, - char* mappedName); - -// Returns information about a name hashing entry from the latest compile. -// Parameters: -// handle: Specifies the compiler -// index: Specifies the index of the name hashing entry to be queried. -// name: Returns a null terminated string containing the user defined name. -// It is assumed that name has enough memory to accomodate the name. -// The size of the buffer required to store the user defined name can -// be obtained by calling ShGetInfo with SH_NAME_MAX_LENGTH. -// hashedName: Returns a null terminated string containing the hashed name of -// the uniform variable, It is assumed that hashedName has enough -// memory to accomodate the name. The size of the buffer required -// to store the name can be obtained by calling ShGetInfo with -// SH_HASHED_NAME_MAX_LENGTH. -COMPILER_EXPORT void ShGetNameHashingEntry(const ShHandle handle, - int index, - char* name, - char* hashedName); +COMPILER_EXPORT const std::map *ShGetNameHashingMap( + const ShHandle handle); // Shader variable inspection. // Returns a pointer to a list of variables of the designated type. @@ -476,17 +372,17 @@ typedef struct int size; } ShVariableInfo; -// Returns 1 if the passed in variables pack in maxVectors following +// Returns true if the passed in variables pack in maxVectors following // the packing rules from the GLSL 1.017 spec, Appendix A, section 7. -// Returns 0 otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS +// Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS // flag above. // Parameters: // maxVectors: the available rows of registers. // varInfoArray: an array of variable info (types and sizes). // varInfoArraySize: the size of the variable array. -COMPILER_EXPORT int ShCheckVariablesWithinPackingLimits( +COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits( int maxVectors, - ShVariableInfo* varInfoArray, + ShVariableInfo *varInfoArray, size_t varInfoArraySize); // Gives the compiler-assigned register for an interface block. @@ -497,7 +393,7 @@ COMPILER_EXPORT int ShCheckVariablesWithinPackingLimits( // interfaceBlockName: Specifies the interface block // indexOut: output variable that stores the assigned register COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle, - const char *interfaceBlockName, + const std::string &interfaceBlockName, unsigned int *indexOut); // Gives the compiler-assigned register for uniforms in the default @@ -509,11 +405,7 @@ COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle, // interfaceBlockName: Specifies the uniform // indexOut: output variable that stores the assigned register COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle, - const char *uniformName, + const std::string &uniformName, unsigned int *indexOut); -#ifdef __cplusplus -} -#endif - #endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h index 9c38647dda..da21c3e76e 100644 --- a/src/3rdparty/angle/include/GLSLANG/ShaderVars.h +++ b/src/3rdparty/angle/include/GLSLANG/ShaderVars.h @@ -52,6 +52,21 @@ struct COMPILER_EXPORT ShaderVariable unsigned int elementCount() const { return std::max(1u, arraySize); } bool isStruct() const { return !fields.empty(); } + // All of the shader's variables are described using nested data + // structures. This is needed in order to disambiguate similar looking + // types, such as two structs containing the same fields, but in + // different orders. "findInfoByMappedName" provides an easy query for + // users to dive into the data structure and fetch the unique variable + // instance corresponding to a dereferencing chain of the top-level + // variable. + // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable + // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]' + // in |originalName|, based on the assumption that |this| defines 'a'. + // If no match is found, return false. + bool findInfoByMappedName(const std::string &mappedFullName, + const ShaderVariable **leafVar, + std::string* originalFullName) const; + GLenum type; GLenum precision; std::string name; @@ -60,6 +75,16 @@ struct COMPILER_EXPORT ShaderVariable bool staticUse; std::vector fields; std::string structName; + + protected: + bool isSameVariableAtLinkTime(const ShaderVariable &other, + bool matchPrecision) const; + + bool operator==(const ShaderVariable &other) const; + bool operator!=(const ShaderVariable &other) const + { + return !operator==(other); + } }; struct COMPILER_EXPORT Uniform : public ShaderVariable @@ -68,6 +93,16 @@ struct COMPILER_EXPORT Uniform : public ShaderVariable ~Uniform(); Uniform(const Uniform &other); Uniform &operator=(const Uniform &other); + bool operator==(const Uniform &other) const; + bool operator!=(const Uniform &other) const + { + return !operator==(other); + } + + // Decide whether two uniforms are the same at shader link time, + // assuming one from vertex shader and the other from fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.5. + bool isSameUniformAtLinkTime(const Uniform &other) const; }; struct COMPILER_EXPORT Attribute : public ShaderVariable @@ -76,6 +111,11 @@ struct COMPILER_EXPORT Attribute : public ShaderVariable ~Attribute(); Attribute(const Attribute &other); Attribute &operator=(const Attribute &other); + bool operator==(const Attribute &other) const; + bool operator!=(const Attribute &other) const + { + return !operator==(other); + } int location; }; @@ -86,6 +126,18 @@ struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable ~InterfaceBlockField(); InterfaceBlockField(const InterfaceBlockField &other); InterfaceBlockField &operator=(const InterfaceBlockField &other); + bool operator==(const InterfaceBlockField &other) const; + bool operator!=(const InterfaceBlockField &other) const + { + return !operator==(other); + } + + // Decide whether two InterfaceBlock fields are the same at shader + // link time, assuming one from vertex shader and the other from + // fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.7. + bool isSameInterfaceBlockFieldAtLinkTime( + const InterfaceBlockField &other) const; bool isRowMajorLayout; }; @@ -94,8 +146,18 @@ struct COMPILER_EXPORT Varying : public ShaderVariable { Varying(); ~Varying(); - Varying(const Varying &other); + Varying(const Varying &otherg); Varying &operator=(const Varying &other); + bool operator==(const Varying &other) const; + bool operator!=(const Varying &other) const + { + return !operator==(other); + } + + // Decide whether two varyings are the same at shader link time, + // assuming one from vertex shader and the other from fragment shader. + // See GLSL ES Spec 3.00.3, sec 4.3.9. + bool isSameVaryingAtLinkTime(const Varying &other) const; InterpolationType interpolation; bool isInvariant; diff --git a/src/3rdparty/angle/include/angle_windowsstore.h b/src/3rdparty/angle/include/angle_windowsstore.h new file mode 100644 index 0000000000..53ec93e037 --- /dev/null +++ b/src/3rdparty/angle/include/angle_windowsstore.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// angle_windowsstore.h: + +#ifndef ANGLE_WINDOWSSTORE_H_ +#define ANGLE_WINDOWSSTORE_H_ + +// The following properties can be set on the CoreApplication to support additional +// ANGLE configuration options. +// +// The Visual Studio sample templates provided with this version of ANGLE have examples +// of how to set these property values. + +// +// Property: EGLNativeWindowTypeProperty +// Type: IInspectable +// Description: Set this property to specify the window type to use for creating a surface. +// If this property is missing, surface creation will fail. +// +const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty"; + +// +// Property: EGLRenderSurfaceSizeProperty +// Type: Size +// Description: Set this property to specify a preferred size in pixels of the render surface. +// The render surface size width and height must be greater than 0. +// If this property is set, then the render surface size is fixed. +// If this property is missing, a default behavior will be provided. +// The default behavior uses the window size if a CoreWindow is specified or +// the size of the SwapChainPanel control if one is specified. +// +const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty"; + +#endif // ANGLE_WINDOWSSTORE_H_ diff --git a/src/3rdparty/angle/src/commit.h b/src/3rdparty/angle/src/commit.h index a2e761b131..08fc893c25 100644 --- a/src/3rdparty/angle/src/commit.h +++ b/src/3rdparty/angle/src/commit.h @@ -7,6 +7,6 @@ // This is a default commit hash header, when git is not available. // -#define ANGLE_COMMIT_HASH "abce76206141" +#define ANGLE_COMMIT_HASH "30d6c255d238" #define ANGLE_COMMIT_HASH_SIZE 12 -#define ANGLE_COMMIT_DATE "2014-09-23 19:37:05 +0000" +#define ANGLE_COMMIT_DATE "2014-11-13 17:37:03 +0000" diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h new file mode 100644 index 0000000000..9e93aeacde --- /dev/null +++ b/src/3rdparty/angle/src/common/NativeWindow.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow.h: Defines NativeWindow, a class for managing and +// performing operations on an EGLNativeWindowType. +// It is used for HWND (Desktop Windows) and IInspectable objects +//(Windows Store Applications). + +#ifndef COMMON_NATIVEWINDOW_H_ +#define COMMON_NATIVEWINDOW_H_ + +#include +#include "common/debug.h" +#include "common/platform.h" + +// DXGISwapChain and DXGIFactory are typedef'd to specific required +// types. The HWND NativeWindow implementation requires IDXGISwapChain +// and IDXGIFactory and the Windows Store NativeWindow +// implementation requires IDXGISwapChain1 and IDXGIFactory2. +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +typedef IDXGISwapChain1 DXGISwapChain; +typedef IDXGIFactory2 DXGIFactory; + +#include +#include +#include +#include + +namespace rx +{ +class InspectableNativeWindow; +} + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +#else +typedef IDXGISwapChain DXGISwapChain; +typedef IDXGIFactory DXGIFactory; +#endif + +namespace rx +{ + +class NativeWindow +{ +public: + explicit NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display); + + bool initialize(); + bool getClientRect(LPRECT rect); + bool isIconic(); + + HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, UINT width, UINT height, + DXGISwapChain** swapChain); + + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } + inline EGLNativeDisplayType getNativeDisplay() const { return mDisplay; } + + private: + EGLNativeWindowType mWindow; + EGLNativeDisplayType mDisplay; + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + std::shared_ptr mImpl; +#endif + +}; + +bool IsValidEGLNativeWindowType(EGLNativeWindowType window); +} + +#endif // COMMON_NATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/angleutils.cpp b/src/3rdparty/angle/src/common/angleutils.cpp index 2673abf30a..c1367c460a 100644 --- a/src/3rdparty/angle/src/common/angleutils.cpp +++ b/src/3rdparty/angle/src/common/angleutils.cpp @@ -5,26 +5,33 @@ // #include "common/angleutils.h" - +#include "debug.h" +#include #include +size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector& outBuffer) +{ + // Attempt to just print to the current buffer + int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + if (len < 0 || static_cast(len) >= outBuffer.size()) + { + // Buffer was not large enough, calculate the required size and resize the buffer + len = vsnprintf(NULL, 0, fmt, vararg); + outBuffer.resize(len + 1); + + // Print again + len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + } + ASSERT(len >= 0); + return static_cast(len); +} + std::string FormatString(const char *fmt, va_list vararg) { static std::vector buffer(512); - // Attempt to just print to the current buffer - int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg); - if (len < 0 || static_cast(len) >= buffer.size()) - { - // Buffer was not large enough, calculate the required size and resize the buffer - len = vsnprintf(NULL, 0, fmt, vararg); - buffer.resize(len + 1); - - // Print again - vsnprintf(&buffer[0], buffer.size(), fmt, vararg); - } - - return std::string(buffer.data(), len); + size_t len = FormatStringIntoVector(fmt, vararg, buffer); + return std::string(&buffer[0], len); } std::string FormatString(const char *fmt, ...) diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h index ddbbd5f501..b343ece5bc 100644 --- a/src/3rdparty/angle/src/common/angleutils.h +++ b/src/3rdparty/angle/src/common/angleutils.h @@ -17,6 +17,7 @@ #include #include #include +#include // A macro to disallow the copy constructor and operator= functions // This must be used in the private: declarations for a class @@ -95,6 +96,13 @@ inline void StructZero(T *obj) memset(obj, 0, sizeof(T)); } +template +inline bool IsMaskFlagSet(T mask, T flag) +{ + // Handles multibit flags as well + return (mask & flag) == flag; +} + inline const char* MakeStaticString(const std::string &str) { static std::set strings; @@ -132,9 +140,12 @@ inline std::string Str(int i) return strstr.str(); } +size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector& buffer); + std::string FormatString(const char *fmt, va_list vararg); std::string FormatString(const char *fmt, ...); +// snprintf is not defined with MSVC prior to to msvc14 #if defined(_MSC_VER) && _MSC_VER < 1900 #define snprintf _snprintf #endif diff --git a/src/3rdparty/angle/src/common/debug.cpp b/src/3rdparty/angle/src/common/debug.cpp index dcad327564..5f55ff1e39 100644 --- a/src/3rdparty/angle/src/common/debug.cpp +++ b/src/3rdparty/angle/src/common/debug.cpp @@ -17,41 +17,211 @@ namespace gl { -#if defined(ANGLE_ENABLE_PERF) -typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR); -#else -typedef void (*PerfOutputFunction)(unsigned int, const wchar_t*); -#endif - -static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg) +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) +// Wraps the D3D9/D3D11 debug annotation functions. +class DebugAnnotationWrapper { -#if defined(ANGLE_ENABLE_PERF) || defined(ANGLE_ENABLE_TRACE) - std::string formattedMessage = FormatString(format, vararg); + public: + DebugAnnotationWrapper() { }; + virtual ~DebugAnnotationWrapper() { }; + virtual void beginEvent(const std::wstring &eventName) = 0; + virtual void endEvent() = 0; + virtual void setMarker(const std::wstring &markerName) = 0; + virtual bool getStatus() = 0; +}; + +#if defined(ANGLE_ENABLE_D3D9) +class D3D9DebugAnnotationWrapper : public DebugAnnotationWrapper +{ + public: + void beginEvent(const std::wstring &eventName) + { + D3DPERF_BeginEvent(0, eventName.c_str()); + } + + void endEvent() + { + D3DPERF_EndEvent(); + } + + void setMarker(const std::wstring &markerName) + { + D3DPERF_SetMarker(0, markerName.c_str()); + } + + bool getStatus() + { + return !!D3DPERF_GetStatus(); + } +}; +#endif // ANGLE_ENABLE_D3D9 + +#if defined(ANGLE_ENABLE_D3D11) +class D3D11DebugAnnotationWrapper : public DebugAnnotationWrapper +{ + public: + + D3D11DebugAnnotationWrapper() + : mInitialized(false), + mD3d11Module(NULL), + mUserDefinedAnnotation(NULL) + { + // D3D11 devices can't be created during DllMain. + // We defer device creation until the object is actually used. + } + + ~D3D11DebugAnnotationWrapper() + { + if (mInitialized) + { + SafeRelease(mUserDefinedAnnotation); + FreeLibrary(mD3d11Module); + } + } + + virtual void beginEvent(const std::wstring &eventName) + { + initializeDevice(); + + mUserDefinedAnnotation->BeginEvent(eventName.c_str()); + } + + virtual void endEvent() + { + initializeDevice(); + + mUserDefinedAnnotation->EndEvent(); + } + + virtual void setMarker(const std::wstring &markerName) + { + initializeDevice(); + + mUserDefinedAnnotation->SetMarker(markerName.c_str()); + } + + virtual bool getStatus() + { + // ID3DUserDefinedAnnotation::GetStatus doesn't work with the Graphics Diagnostics tools in Visual Studio 2013. + +#if defined(_DEBUG) && defined(ANGLE_ENABLE_WINDOWS_STORE) + // In the Windows Store, we can use IDXGraphicsAnalysis. The call to GetDebugInterface1 only succeeds if the app is under capture. + // This should only be called in DEBUG mode. + // If an app links against DXGIGetDebugInterface1 in release mode then it will fail Windows Store ingestion checks. + IDXGraphicsAnalysis* graphicsAnalysis; + DXGIGetDebugInterface1(0, IID_PPV_ARGS(&graphicsAnalysis)); + bool underCapture = (graphicsAnalysis != NULL); + SafeRelease(graphicsAnalysis); + return underCapture; #endif -#if defined(ANGLE_ENABLE_PERF) + // Otherwise, we have to return true here. + return true; + } + + protected: + + void initializeDevice() + { + if (!mInitialized) + { +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); + ASSERT(mD3d11Module); + + PFN_D3D11_CREATE_DEVICE D3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(mD3d11Module, "D3D11CreateDevice"); + ASSERT(D3D11CreateDevice != NULL); +#endif // !ANGLE_ENABLE_WINDOWS_STORE + + ID3D11Device* device = NULL; + ID3D11DeviceContext* context = NULL; + + HRESULT hr = E_FAIL; + + // Create a D3D_DRIVER_TYPE_NULL device, which is much cheaper than other types of device. + hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context); + ASSERT(SUCCEEDED(hr)); + + hr = context->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast(&mUserDefinedAnnotation)); + ASSERT(SUCCEEDED(hr) && mUserDefinedAnnotation != NULL); + + SafeRelease(device); + SafeRelease(context); + + mInitialized = true; + } + } + + bool mInitialized; + HMODULE mD3d11Module; + ID3DUserDefinedAnnotation* mUserDefinedAnnotation; +}; +#endif // ANGLE_ENABLE_D3D11 + +static DebugAnnotationWrapper* g_DebugAnnotationWrapper = NULL; + +void InitializeDebugAnnotations() +{ +#if defined(ANGLE_ENABLE_D3D9) + g_DebugAnnotationWrapper = new D3D9DebugAnnotationWrapper(); +#elif defined(ANGLE_ENABLE_D3D11) + // If the project uses D3D9 then we can use the D3D9 debug annotations, even with the D3D11 renderer. + // However, if D3D9 is unavailable (e.g. in Windows Store), then we use D3D11 debug annotations. + // The D3D11 debug annotations are methods on ID3DUserDefinedAnnotation, which is implemented by the DeviceContext. + // This doesn't have to be the same DeviceContext that the renderer uses, though. + g_DebugAnnotationWrapper = new D3D11DebugAnnotationWrapper(); +#endif +} + +void UninitializeDebugAnnotations() +{ + if (g_DebugAnnotationWrapper != NULL) + { + SafeDelete(g_DebugAnnotationWrapper); + } +} + +#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS + +enum DebugTraceOutputType +{ + DebugTraceOutputTypeNone, + DebugTraceOutputTypeSetMarker, + DebugTraceOutputTypeBeginEvent +}; + +static void output(bool traceInDebugOnly, DebugTraceOutputType outputType, const char *format, va_list vararg) +{ +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) + static std::vector buffer(512); + if (perfActive()) { - // The perf function only accepts wide strings, widen the ascii message - static std::wstring wideMessage; - if (wideMessage.capacity() < formattedMessage.length()) + size_t len = FormatStringIntoVector(format, vararg, buffer); + std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); + + switch (outputType) { - wideMessage.reserve(formattedMessage.size()); + case DebugTraceOutputTypeNone: + break; + case DebugTraceOutputTypeBeginEvent: + g_DebugAnnotationWrapper->beginEvent(formattedWideMessage); + break; + case DebugTraceOutputTypeSetMarker: + g_DebugAnnotationWrapper->setMarker(formattedWideMessage); + break; } - - wideMessage.assign(formattedMessage.begin(), formattedMessage.end()); - - perfFunc(0, wideMessage.c_str()); } -#endif // ANGLE_ENABLE_PERF +#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS -#if defined(ANGLE_ENABLE_TRACE) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) #if defined(NDEBUG) - if (traceFileDebugOnly) + if (traceInDebugOnly) { return; } #endif // NDEBUG + std::string formattedMessage = FormatString(format, vararg); static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); if (file) @@ -60,25 +230,29 @@ static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const c file.flush(); } -#endif // ANGLE_ENABLE_TRACE +#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) + OutputDebugStringA(formattedMessage.c_str()); +#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER + +#endif // ANGLE_ENABLE_DEBUG_TRACE } -void trace(bool traceFileDebugOnly, const char *format, ...) +void trace(bool traceInDebugOnly, const char *format, ...) { va_list vararg; va_start(vararg, format); -#if defined(ANGLE_ENABLE_PERF) - output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg); +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) + output(traceInDebugOnly, DebugTraceOutputTypeSetMarker, format, vararg); #else - output(traceFileDebugOnly, NULL, format, vararg); + output(traceInDebugOnly, DebugTraceOutputTypeNone, format, vararg); #endif va_end(vararg); } bool perfActive() { -#if defined(ANGLE_ENABLE_PERF) - static bool active = D3DPERF_GetStatus() != 0; +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) + static bool active = g_DebugAnnotationWrapper->getStatus(); return active; #else return false; @@ -87,26 +261,28 @@ bool perfActive() ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) { -#if defined(ANGLE_ENABLE_PERF) -#if !defined(ANGLE_ENABLE_TRACE) +#if !defined(ANGLE_ENABLE_DEBUG_TRACE) if (!perfActive()) { return; } -#endif // !ANGLE_ENABLE_TRACE +#endif // !ANGLE_ENABLE_DEBUG_TRACE va_list vararg; va_start(vararg, format); - output(true, reinterpret_cast(D3DPERF_BeginEvent), format, vararg); +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) + output(true, DebugTraceOutputTypeBeginEvent, format, vararg); +#else + output(true, DebugTraceOutputTypeNone, format, vararg); +#endif // ANGLE_ENABLE_DEBUG_ANNOTATIONS va_end(vararg); -#endif // ANGLE_ENABLE_PERF } ScopedPerfEventHelper::~ScopedPerfEventHelper() { -#if defined(ANGLE_ENABLE_PERF) +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) if (perfActive()) { - D3DPERF_EndEvent(); + g_DebugAnnotationWrapper->endEvent(); } #endif } diff --git a/src/3rdparty/angle/src/common/debug.h b/src/3rdparty/angle/src/common/debug.h index bf2bca8f24..c177f51314 100644 --- a/src/3rdparty/angle/src/common/debug.h +++ b/src/3rdparty/angle/src/common/debug.h @@ -20,8 +20,8 @@ namespace gl { - // Outputs text to the debugging log - void trace(bool traceFileDebugOnly, const char *format, ...); + // Outputs text to the debugging log, or the debugging window + void trace(bool traceInDebugOnly, const char *format, ...); // Returns whether D3DPERF is active. bool perfActive(); @@ -36,31 +36,34 @@ namespace gl private: DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper); }; + + void InitializeDebugAnnotations(); + void UninitializeDebugAnnotations(); } // A macro to output a trace of a function call and its arguments to the debugging log -#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #define TRACE(message, ...) gl::trace(true, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define TRACE(message, ...) (void(0)) #endif // A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing. -#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define FIXME(message, ...) (void(0)) #endif // A macro to output a function call and its arguments to the debugging log, in case of error. -#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #define ERR(message, ...) gl::trace(false, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) #else #define ERR(message, ...) (void(0)) #endif // A macro to log a performance event around a scope. -#if defined(ANGLE_ENABLE_TRACE) || defined(ANGLE_ENABLE_PERF) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) #if defined(_MSC_VER) #define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__); #else @@ -83,7 +86,7 @@ namespace gl #define UNUSED_ASSERTION_VARIABLE(variable) ((void)variable) #endif -#ifndef ANGLE_ENABLE_TRACE +#ifndef ANGLE_ENABLE_DEBUG_TRACE #define UNUSED_TRACE_VARIABLE(variable) ((void)variable) #else #define UNUSED_TRACE_VARIABLE(variable) @@ -128,7 +131,7 @@ namespace gl #endif // A macro functioning as a compile-time assert to validate constant conditions -#if defined(_MSC_VER) && _MSC_VER >= 1600 +#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__GNUC__) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)) #define META_ASSERT_MSG(condition, msg) static_assert(condition, msg) #else #define META_ASSERT_CONCAT(a, b) a ## b diff --git a/src/3rdparty/angle/src/common/features.h b/src/3rdparty/angle/src/common/features.h new file mode 100644 index 0000000000..b49a0ee852 --- /dev/null +++ b/src/3rdparty/angle/src/common/features.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#define ANGLE_DISABLED 0 +#define ANGLE_ENABLED 1 + +// Feature defaults + +// Direct3D9EX +// The "Debug This Pixel..." feature in PIX often fails when using the +// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 +// machine, define "ANGLE_D3D9EX=0" in your project file. +#if !defined(ANGLE_D3D9EX) +#define ANGLE_D3D9EX ANGLE_ENABLED +#endif + +// Vsync +// ENABLED allows Vsync to be configured at runtime +// DISABLED disallows Vsync +#if !defined(ANGLE_VSYNC) +#define ANGLE_VSYNC ANGLE_ENABLED +#endif + +// Program binary loading +#if !defined(ANGLE_PROGRAM_BINARY_LOAD) +#define ANGLE_PROGRAM_BINARY_LOAD ANGLE_ENABLED +#endif + +// Shader debug info +#if !defined(ANGLE_SHADER_DEBUG_INFO) +#define ANGLE_SHADER_DEBUG_INFO ANGLE_DISABLED +#endif diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h index 52f2bc1c0e..a1717892fd 100644 --- a/src/3rdparty/angle/src/common/mathutil.h +++ b/src/3rdparty/angle/src/common/mathutil.h @@ -109,7 +109,7 @@ inline unsigned int unorm(float x) inline bool supportsSSE2() { -#ifdef ANGLE_PLATFORM_WINDOWS +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) static bool checked = false; static bool supports = false; @@ -118,7 +118,6 @@ inline bool supportsSSE2() return supports; } -#if defined(_M_IX86) || defined(_M_AMD64) // ARM doesn't provide __cpuid() int info[4]; __cpuid(info, 0); @@ -128,7 +127,6 @@ inline bool supportsSSE2() supports = (info[3] >> 26) & 1; } -#endif checked = true; diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h index b53394f337..0001e7142e 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h @@ -11,9 +11,6 @@ #if defined(_WIN32) || defined(_WIN64) # define ANGLE_PLATFORM_WINDOWS 1 -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -# define ANGLE_PLATFORM_WINRT 1 -# endif #elif defined(__APPLE__) # define ANGLE_PLATFORM_APPLE 1 # define ANGLE_PLATFORM_POSIX 1 @@ -37,6 +34,9 @@ #endif #ifdef ANGLE_PLATFORM_WINDOWS +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +# define ANGLE_ENABLE_WINDOWS_STORE 1 +# endif # ifndef STRICT # define STRICT 1 # endif @@ -50,7 +50,7 @@ # include # include -# if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_PERF) +# if defined(ANGLE_ENABLE_D3D9) # include # if !defined(COMPILER_IMPLEMENTATION) # include @@ -62,13 +62,26 @@ # include # include # include -# if _MSC_VER >= 1700 +# if defined(_MSC_VER) && (_MSC_VER >= 1700) +# include # include # endif # if !defined(COMPILER_IMPLEMENTATION) # include # endif -# if defined(__MINGW32__) +# endif + +# if defined(ANGLE_ENABLE_WINDOWS_STORE) +# include +# if defined(_DEBUG) +# if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) +# include +# endif +# include +# endif +# endif + +# if defined(__MINGW32__) // Missing defines on MinGW typedef enum D3D11_MAP_FLAG { D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000L @@ -78,8 +91,68 @@ typedef struct D3D11_QUERY_DATA_SO_STATISTICS UINT64 NumPrimitivesWritten; UINT64 PrimitivesStorageNeeded; } D3D11_QUERY_DATA_SO_STATISTICS; -# endif -# endif +typedef HRESULT (WINAPI *PFN_D3D11_CREATE_DEVICE)( + IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL *, + UINT FeatureLevels, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); +#define D3D11_MESSAGE_CATEGORY UINT +#define D3D11_MESSAGE_SEVERITY UINT +#define D3D11_MESSAGE_ID UINT +struct D3D11_MESSAGE; +typedef struct D3D11_INFO_QUEUE_FILTER_DESC +{ + UINT NumCategories; + D3D11_MESSAGE_CATEGORY *pCategoryList; + UINT NumSeverities; + D3D11_MESSAGE_SEVERITY *pSeverityList; + UINT NumIDs; + D3D11_MESSAGE_ID *pIDList; +} D3D11_INFO_QUEUE_FILTER_DESC; +typedef struct D3D11_INFO_QUEUE_FILTER +{ + D3D11_INFO_QUEUE_FILTER_DESC AllowList; + D3D11_INFO_QUEUE_FILTER_DESC DenyList; +} D3D11_INFO_QUEUE_FILTER; +static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; +MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown +{ +public: + virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; + virtual void __stdcall ClearStoredMessages() = 0; + virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; + virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; + virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; + virtual UINT64 __stdcall GetNumStoredMessages() = 0; + virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; + virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; + virtual UINT64 __stdcall GetMessageCountLimit() = 0; + virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; + virtual void __stdcall ClearStorageFilter() = 0; + virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; + virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; + virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual void __stdcall PopStorageFilter() = 0; + virtual UINT __stdcall GetStorageFilterStackSize() = 0; + virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; + virtual void __stdcall ClearRetrievalFilter() = 0; + virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; + virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; + virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; + virtual void __stdcall PopRetrievalFilter() = 0; + virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; + virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; + virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; + virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; + virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; + virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; + virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; + virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; + virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; + virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; + virtual BOOL __stdcall GetMuteDebugOutput() = 0; +}; +#endif // __MINGW32__ # undef near # undef far diff --git a/src/3rdparty/angle/src/common/tls.cpp b/src/3rdparty/angle/src/common/tls.cpp index c46fab5303..cb1b32d325 100644 --- a/src/3rdparty/angle/src/common/tls.cpp +++ b/src/3rdparty/angle/src/common/tls.cpp @@ -10,29 +10,50 @@ #include -#if defined(ANGLE_PLATFORM_WINRT) +#ifdef ANGLE_ENABLE_WINDOWS_STORE #include -std::vector *tls = nullptr; -std::vector *freeIndices = nullptr; +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace Windows::Foundation; +using namespace ABI::Windows::System::Threading; + +// Thread local storage for Windows Store support +typedef vector ThreadLocalData; + +static __declspec(thread) ThreadLocalData* currentThreadData = nullptr; +static set allThreadData; +static DWORD nextTlsIndex = 0; +static vector freeTlsIndices; + #endif TLSIndex CreateTLSIndex() { TLSIndex index; -#if defined(ANGLE_PLATFORM_WINRT) - if (!tls) - tls = new std::vector; - if (freeIndices && !freeIndices->empty()) { - index = freeIndices->back(); - freeIndices->pop_back(); - return index; - } else { - tls->push_back(nullptr); - return tls->size() - 1; +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + if (!freeTlsIndices.empty()) + { + DWORD result = freeTlsIndices.back(); + freeTlsIndices.pop_back(); + index = result; } -#elif defined(ANGLE_PLATFORM_WINDOWS) + else + { + index = nextTlsIndex++; + } +#else index = TlsAlloc(); +#endif + #elif defined(ANGLE_PLATFORM_POSIX) // Create global pool key if ((pthread_key_create(&index, NULL)) != 0) @@ -53,13 +74,23 @@ bool DestroyTLSIndex(TLSIndex index) return false; } -#if defined(ANGLE_PLATFORM_WINRT) - if (!freeIndices) - freeIndices = new std::vector; - freeIndices->push_back(index); +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + assert(index < nextTlsIndex); + assert(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end()); + + freeTlsIndices.push_back(index); + for (auto threadData : allThreadData) + { + if (threadData->size() > index) + { + threadData->at(index) = nullptr; + } + } return true; -#elif ANGLE_PLATFORM_WINDOWS +#else return (TlsFree(index) == TRUE); +#endif #elif defined(ANGLE_PLATFORM_POSIX) return (pthread_key_delete(index) == 0); #endif @@ -73,11 +104,25 @@ bool SetTLSValue(TLSIndex index, void *value) return false; } -#if defined(ANGLE_PLATFORM_WINRT) - tls->at(index) = value; +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + ThreadLocalData* threadData = currentThreadData; + if (!threadData) + { + threadData = new ThreadLocalData(index + 1, nullptr); + allThreadData.insert(threadData); + currentThreadData = threadData; + } + else if (threadData->size() <= index) + { + threadData->resize(index + 1, nullptr); + } + + threadData->at(index) = value; return true; -#elif defined(ANGLE_PLATFORM_WINDOWS) +#else return (TlsSetValue(index, value) == TRUE); +#endif #elif defined(ANGLE_PLATFORM_POSIX) return (pthread_setspecific(index, value) == 0); #endif @@ -85,18 +130,26 @@ bool SetTLSValue(TLSIndex index, void *value) void *GetTLSValue(TLSIndex index) { -#if !defined(ANGLE_PLATFORM_WINRT) // Valid on WinRT, as Alloc handles the index creation assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); -#endif if (index == TLS_INVALID_INDEX) { return NULL; } -#if defined(ANGLE_PLATFORM_WINRT) - return tls->at(index); -#elif defined(ANGLE_PLATFORM_WINDOWS) +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + ThreadLocalData* threadData = currentThreadData; + if (threadData && threadData->size() > index) + { + return threadData->at(index); + } + else + { + return nullptr; + } +#else return TlsGetValue(index); +#endif #elif defined(ANGLE_PLATFORM_POSIX) return pthread_getspecific(index); #endif diff --git a/src/3rdparty/angle/src/common/tls.h b/src/3rdparty/angle/src/common/tls.h index c40ae1a061..8a06e92d1a 100644 --- a/src/3rdparty/angle/src/common/tls.h +++ b/src/3rdparty/angle/src/common/tls.h @@ -11,11 +11,15 @@ #include "common/platform.h" -#if defined(ANGLE_PLATFORM_WINRT) - typedef size_t TLSIndex; -# define TLS_OUT_OF_INDEXES (static_cast(-1)) -# define TLS_INVALID_INDEX TLS_OUT_OF_INDEXES -#elif defined(ANGLE_PLATFORM_WINDOWS) +#ifdef ANGLE_PLATFORM_WINDOWS + +// TLS does not exist for Windows Store and needs to be emulated +# ifdef ANGLE_ENABLE_WINDOWS_STORE +# define TLS_OUT_OF_INDEXES -1 +# ifndef CREATE_SUSPENDED +# define CREATE_SUSPENDED 0x00000004 +# endif +# endif typedef DWORD TLSIndex; # define TLS_INVALID_INDEX (TLS_OUT_OF_INDEXES) #elif defined(ANGLE_PLATFORM_POSIX) @@ -28,6 +32,9 @@ # error Unsupported platform. #endif +// TODO(kbr): for POSIX platforms this will have to be changed to take +// in a destructor function pointer, to allow the thread-local storage +// to be properly deallocated upon thread exit. TLSIndex CreateTLSIndex(); bool DestroyTLSIndex(TLSIndex index); diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp index 4b8e325d22..9d797a6612 100644 --- a/src/3rdparty/angle/src/common/utilities.cpp +++ b/src/3rdparty/angle/src/common/utilities.cpp @@ -9,17 +9,16 @@ #include "common/utilities.h" #include "common/mathutil.h" #include "common/platform.h" -#if defined(ANGLE_PLATFORM_WINRT) -# include -# include -# include -# include - using namespace Microsoft::WRL; - using namespace ABI::Windows::Storage; -#endif #include +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +# include +# include +# include +# include +#endif + namespace gl { @@ -447,50 +446,10 @@ int VariableSortOrder(GLenum type) } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) std::string getTempPath() { -#if defined(ANGLE_PLATFORM_WINRT) - static std::string path; - - while (path.empty()) - { - ComPtr factory; - Wrappers::HStringReference classId(RuntimeClass_Windows_Storage_ApplicationData); - HRESULT result = RoGetActivationFactory(classId.Get(), IID_PPV_ARGS(&factory)); - if (FAILED(result)) - break; - - ComPtr applicationData; - result = factory->get_Current(&applicationData); - if (FAILED(result)) - break; - - ComPtr storageFolder; - result = applicationData->get_LocalFolder(&storageFolder); - if (FAILED(result)) - break; - - ComPtr localFolder; - result = storageFolder.As(&localFolder); - if (FAILED(result)) - break; - - HSTRING localFolderPath; - result = localFolder->get_Path(&localFolderPath); - if (FAILED(result)) - break; - - std::wstring_convert< std::codecvt_utf8 > converter; - path = converter.to_bytes(WindowsGetStringRawBuffer(localFolderPath, NULL)); - if (path.empty()) - { - UNREACHABLE(); - break; - } - } - - return path; -#elif defined(ANGLE_PLATFORM_WINDOWS) +#ifdef ANGLE_PLATFORM_WINDOWS char path[MAX_PATH]; DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); if (pathLen == 0) @@ -525,3 +484,33 @@ void writeFile(const char* path, const void* content, size_t size) fwrite(content, sizeof(char), size, file); fclose(file); } +#endif // !ANGLE_ENABLE_WINDOWS_STORE + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + +void Sleep(unsigned long dwMilliseconds) +{ + static HANDLE singletonEvent = nullptr; + HANDLE sleepEvent = singletonEvent; + if (!sleepEvent) + { + sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); + + if (!sleepEvent) + return; + + HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr); + + if (previousEvent) + { + // Back out if multiple threads try to demand create at the same time. + CloseHandle(sleepEvent); + sleepEvent = previousEvent; + } + } + + // Emulate sleep by waiting with timeout on an event that is never signalled. + WaitForSingleObjectEx(sleepEvent, dwMilliseconds, false); +} + +#endif // ANGLE_ENABLE_WINDOWS_STORE diff --git a/src/3rdparty/angle/src/common/utilities.h b/src/3rdparty/angle/src/common/utilities.h index a823184ecd..2cf6bed176 100644 --- a/src/3rdparty/angle/src/common/utilities.h +++ b/src/3rdparty/angle/src/common/utilities.h @@ -46,7 +46,13 @@ template outT uiround(GLfloat value) { return static_cast( } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) std::string getTempPath(); void writeFile(const char* path, const void* data, size_t size); +#endif + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +void Sleep(_In_ unsigned long dwMilliseconds); +#endif #endif // LIBGLESV2_UTILITIES_H diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp new file mode 100644 index 0000000000..2440747260 --- /dev/null +++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp @@ -0,0 +1,66 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// NativeWindow.cpp: Handler for managing HWND native window types. + +#include "common/NativeWindow.h" +#include "common/debug.h" + +namespace rx +{ +bool IsValidEGLNativeWindowType(EGLNativeWindowType window) +{ + return (IsWindow(window) == TRUE); +} + +NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) : mWindow(window), mDisplay(display) +{ +} + +bool NativeWindow::initialize() +{ + return true; +} + +bool NativeWindow::getClientRect(LPRECT rect) +{ + return GetClientRect(mWindow, rect) == TRUE; +} + +bool NativeWindow::isIconic() +{ + return IsIconic(mWindow) == TRUE; +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, + DXGI_FORMAT format, unsigned int width, unsigned int height, + DXGISwapChain** swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; + swapChainDesc.BufferCount = 1; + swapChainDesc.BufferDesc.Format = format; + swapChainDesc.BufferDesc.Width = width; + swapChainDesc.BufferDesc.Height = height; + swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; + swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.Flags = 0; + swapChainDesc.OutputWindow = mWindow; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.Windowed = TRUE; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + return factory->CreateSwapChain(device, &swapChainDesc, swapChain); +} +} diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp new file mode 100644 index 0000000000..9b65c15625 --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp @@ -0,0 +1,200 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. + +#include +#include "common/winrt/CoreWindowNativeWindow.h" +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ + +typedef ITypedEventHandler SizeChangedHandler; + +CoreWindowNativeWindow::~CoreWindowNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) +{ + ComPtr props = propertySet; + ComPtr win = window; + ComPtr displayInformation = display; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mCoreWindow); + } + + if (SUCCEEDED(result)) + { + result = displayInformation.As(&mDisplayInformation); + } + + if (SUCCEEDED(result)) + { +#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP + ComPtr displayInformation2; + result = mDisplayInformation.As(&displayInformation2); + ASSERT(SUCCEEDED(result)); + + result = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); + ASSERT(SUCCEEDED(result)); +#else + ABI::Windows::Graphics::Display::ResolutionScale resolutionScale; + result = mDisplayInformation->get_ResolutionScale(&resolutionScale); + ASSERT(SUCCEEDED(result)); + + mScaleFactor = DOUBLE(resolutionScale) / 100.0; +#endif + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output occurs automatically because if + // the scaling mode setting DXGI_SCALING_STRETCH on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + mSupportsSwapChainResize = false; + } + else + { + ABI::Windows::Foundation::Rect rect; + HRESULT result = mCoreWindow->get_Bounds(&rect); + if (SUCCEEDED(result)) + { + LONG width = std::floor(rect.Width * mScaleFactor + 0.5); + LONG height = std::floor(rect.Height * mScaleFactor + 0.5); + mClientRect = { 0, 0, width, height }; + } + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool CoreWindowNativeWindow::registerForSizeChangeEvents() +{ + HRESULT result = mCoreWindow->add_SizeChanged(Callback(this, &CoreWindowNativeWindow::onSizeChanged).Get(), + &mSizeChangedEventToken); + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void CoreWindowNativeWindow::unregisterForSizeChangeEvents() +{ + if (mCoreWindow) + { + (void)mCoreWindow->remove_SizeChanged(mSizeChangedEventToken); + } + mSizeChangedEventToken.value = 0; +} + +HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + + *swapChain = nullptr; + + ComPtr newSwapChain; + HRESULT result = factory->CreateSwapChainForCoreWindow(device, mCoreWindow.Get(), &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + if (SUCCEEDED(result)) + { + +#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // This block is disabled for Qt applications, as the resize events are expected + // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On + // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed + // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. + if (newSwapChain->ResizeBuffers(swapChainDesc.BufferCount, swapChainDesc.Width, swapChainDesc.Height, swapChainDesc.Format, DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) == DXGI_ERROR_UNSUPPORTED) + { + mSupportsSwapChainResize = false; + } +#endif // (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + + result = newSwapChain.CopyTo(swapChain); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +// Basically, this shouldn't be used on Phone +HRESULT CoreWindowNativeWindow::onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *e) +{ + ABI::Windows::Foundation::Size size; + if (SUCCEEDED(e->get_Size(&size))) + { + SIZE windowSizeInPixels = { + std::floor(size.Width * mScaleFactor + 0.5), + std::floor(size.Height * mScaleFactor + 0.5) + }; + setNewClientSize(windowSizeInPixels); + } + + return S_OK; +} +} diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h new file mode 100644 index 0000000000..1c5512417d --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// CoreWindowNativeWindow.h: NativeWindow for managing ICoreWindow native window types. + +#ifndef COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ +#define COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ + +#include "common/winrt/InspectableNativeWindow.h" +#include +#include + +namespace rx +{ + +class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~CoreWindowNativeWindow(); + + bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + + private: + HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); + + ComPtr mCoreWindow; + ComPtr mDisplayInformation; + ComPtr> mPropertyMap; +}; + +} + +#endif // COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp new file mode 100644 index 0000000000..0589f6dce5 --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp @@ -0,0 +1,274 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.cpp: NativeWindow base class for managing IInspectable native window types. + +#include "common/winrt/CoreWindowNativeWindow.h" +#include "common/winrt/SwapChainPanelNativeWindow.h" + +namespace rx +{ +NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) + : mWindow(window), mDisplay(display) +{ +} + +bool NativeWindow::initialize() +{ + // If the native window type is a IPropertySet, extract the + // EGLNativeWindowType (IInspectable) and initialize the + // proper host with this IPropertySet. + ComPtr propertySet; + ComPtr eglNativeWindow; + if (IsEGLConfiguredPropertySet(mWindow, &propertySet, &eglNativeWindow)) + { + // A property set was found and the EGLNativeWindowType was + // retrieved. The mWindow member of the host to must be updated + // to use the EGLNativeWindowType specified in the property set. + // mWindow is treated as a raw pointer not an AddRef'd interface, so + // the old mWindow does not need a Release() before this assignment. + mWindow = eglNativeWindow.Get(); + } + + ComPtr coreWindow; + ComPtr swapChainPanel; + if (IsCoreWindow(mWindow, &coreWindow)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); + } + } + else if (IsSwapChainPanel(mWindow, &swapChainPanel)) + { + mImpl = std::make_shared(); + if (mImpl) + { + return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); + } + } + else + { + ERR("Invalid IInspectable EGLNativeWindowType detected. Valid IInspectables include ICoreWindow, ISwapChainPanel and IPropertySet"); + } + + return false; +} + +bool NativeWindow::getClientRect(RECT *rect) +{ + if (mImpl) + { + return mImpl->getClientRect(rect); + } + + return false; +} + +bool NativeWindow::isIconic() +{ + return false; +} + +HRESULT NativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (mImpl) + { + return mImpl->createSwapChain(device, factory, format, width, height, swapChain); + } + + return E_UNEXPECTED; +} + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr coreWin; + if (SUCCEEDED(win.As(&coreWin))) + { + if (coreWindow != nullptr) + { + *coreWindow = coreWin.Detach(); + } + return true; + } + + return false; +} + +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel) +{ + if (!window) + { + return false; + } + + ComPtr win = window; + ComPtr panel; + if (SUCCEEDED(win.As(&panel))) + { + if (swapChainPanel != nullptr) + { + *swapChainPanel = panel.Detach(); + } + return true; + } + + return false; +} + +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet, IInspectable **eglNativeWindow) +{ + if (!window) + { + return false; + } + + ComPtr props = window; + ComPtr propSet; + ComPtr nativeWindow; + ComPtr> propMap; + boolean hasEglNativeWindowPropertyKey = false; + + HRESULT result = props.As(&propSet); + if (SUCCEEDED(result)) + { + result = propSet.As(&propMap); + } + + // Look for the presence of the EGLNativeWindowType in the property set + if (SUCCEEDED(result)) + { + result = propMap->HasKey(HStringReference(EGLNativeWindowTypeProperty).Get(), &hasEglNativeWindowPropertyKey); + } + + // If the IPropertySet does not contain the required EglNativeWindowType key, the property set is + // considered invalid. + if (SUCCEEDED(result) && !hasEglNativeWindowPropertyKey) + { + ERR("Could not find EGLNativeWindowTypeProperty in IPropertySet. Valid EGLNativeWindowTypeProperty values include ICoreWindow"); + return false; + } + + // The EglNativeWindowType property exists, so retreive the IInspectable that represents the EGLNativeWindowType + if (SUCCEEDED(result) && hasEglNativeWindowPropertyKey) + { + result = propMap->Lookup(HStringReference(EGLNativeWindowTypeProperty).Get(), &nativeWindow); + } + + if (SUCCEEDED(result)) + { + if (propertySet != nullptr) + { + result = propSet.CopyTo(propertySet); + } + } + + if (SUCCEEDED(result)) + { + if (eglNativeWindow != nullptr) + { + result = nativeWindow.CopyTo(eglNativeWindow); + } + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +// A Valid EGLNativeWindowType IInspectable can only be: +// +// ICoreWindow +// IPropertySet +// +// Anything else will be rejected as an invalid IInspectable. +bool IsValidEGLNativeWindowType(EGLNativeWindowType window) +{ + return IsCoreWindow(window) || IsSwapChainPanel(window) || IsEGLConfiguredPropertySet(window); +} + +// Attempts to read an optional SIZE property value that is assumed to be in the form of +// an ABI::Windows::Foundation::Size. This function validates the Size value before returning +// it to the caller. +// +// Possible return values are: +// S_OK, valueExists == true - optional SIZE value was successfully retrieved and validated +// S_OK, valueExists == false - optional SIZE value was not found +// E_INVALIDARG, valueExists = false - optional SIZE value was malformed in the property set. +// * Incorrect property type ( must be PropertyType_Size) +// * Invalid property value (width/height must be > 0) +// Additional errors may be returned from IMap or IPropertyValue +// +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists) +{ + if (!propertyMap || !propertyName || !value || !valueExists) + { + return false; + } + + // Assume that the value does not exist + *valueExists = false; + *value = { 0, 0 }; + + ComPtr propertyValue; + ABI::Windows::Foundation::PropertyType propertyType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty; + Size sizeValue = { 0, 0 }; + boolean hasKey = false; + + HRESULT result = propertyMap->HasKey(HStringReference(propertyName).Get(), &hasKey); + if (SUCCEEDED(result) && !hasKey) + { + // Value does not exist, so return S_OK and set the exists parameter to false to indicate + // that a the optional property does not exist. + *valueExists = false; + return S_OK; + } + + if (SUCCEEDED(result)) + { + result = propertyMap->Lookup(HStringReference(propertyName).Get(), &propertyValue); + } + + if (SUCCEEDED(result)) + { + result = propertyValue->get_Type(&propertyType); + } + + // Check if the expected Size property is of PropertyType_Size type. + if (SUCCEEDED(result) && propertyType == ABI::Windows::Foundation::PropertyType::PropertyType_Size) + { + if (SUCCEEDED(propertyValue->GetSize(&sizeValue)) && (sizeValue.Width > 0 && sizeValue.Height > 0)) + { + // A valid property value exists + *value = { static_cast(sizeValue.Width), static_cast(sizeValue.Height) }; + *valueExists = true; + result = S_OK; + } + else + { + // An invalid Size property was detected. Width/Height values must > 0 + result = E_INVALIDARG; + } + } + else + { + // An invalid property type was detected. Size property must be of PropertyType_Size + result = E_INVALIDARG; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h new file mode 100644 index 0000000000..402941a788 --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// InspectableNativeWindow.h: Host specific implementation interface for +// managing IInspectable native window types. + +#ifndef COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ +#define COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ + +#include "common/platform.h" +#include "common/NativeWindow.h" +#include "angle_windowsstore.h" + +#include +#include + +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +class InspectableNativeWindow +{ + public: + InspectableNativeWindow() : + mSupportsSwapChainResize(true), + mRequiresSwapChainScaling(false), + mClientRectChanged(false), + mClientRect({0,0,0,0}), + mNewClientRect({0,0,0,0}), + mScaleFactor(1.0) + { + mSizeChangedEventToken.value = 0; + } + virtual ~InspectableNativeWindow(){} + + virtual bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) = 0; + virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; + virtual bool registerForSizeChangeEvents() = 0; + virtual void unregisterForSizeChangeEvents() = 0; + virtual HRESULT scaleSwapChain(const SIZE& newSize) { return S_OK; } + + bool getClientRect(RECT *rect) + { + if (mClientRectChanged && mSupportsSwapChainResize) + { + mClientRect = mNewClientRect; + mClientRectChanged = false; + } + + *rect = mClientRect; + + return true; + } + + void setNewClientSize(const SIZE &newSize) + { + if (mSupportsSwapChainResize && !mRequiresSwapChainScaling) + { + mNewClientRect = { 0, 0, newSize.cx, newSize.cy }; + mClientRectChanged = true; + } + + if (mRequiresSwapChainScaling) + { + scaleSwapChain(newSize); + } + } + +protected: + bool mSupportsSwapChainResize; + bool mRequiresSwapChainScaling; + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; + DOUBLE mScaleFactor; + + EventRegistrationToken mSizeChangedEventToken; +}; + +bool IsCoreWindow(EGLNativeWindowType window, ComPtr *coreWindow = nullptr); +bool IsSwapChainPanel(EGLNativeWindowType window, ComPtr *swapChainPanel = nullptr); +bool IsEGLConfiguredPropertySet(EGLNativeWindowType window, ABI::Windows::Foundation::Collections::IPropertySet **propertySet = nullptr, IInspectable **inspectable = nullptr); +HRESULT GetOptionalSizePropertyValue(const ComPtr>& propertyMap, const wchar_t *propertyName, SIZE *value, bool *valueExists); +} +#endif // COMMON_WINRT_INSPECTABLENATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp new file mode 100644 index 0000000000..268dfbd8f0 --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp @@ -0,0 +1,226 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.cpp: NativeWindow for managing ISwapChainPanel native window types. + +#include "common/winrt/SwapChainPanelNativeWindow.h" +#include +#include +using namespace ABI::Windows::Foundation::Collections; + +namespace rx +{ +SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() +{ + unregisterForSizeChangeEvents(); +} + +bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) +{ + ComPtr props = propertySet; + ComPtr win = window; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; + + // IPropertySet is an optional parameter and can be null. + // If one is specified, cache as an IMap and read the properties + // used for initial host initialization. + if (propertySet) + { + result = props.As(&mPropertyMap); + if (SUCCEEDED(result)) + { + // The EGLRenderSurfaceSizeProperty is optional and may be missing. The IPropertySet + // was prevalidated to contain the EGLNativeWindowType before being passed to + // this host. + result = GetOptionalSizePropertyValue(mPropertyMap, EGLRenderSurfaceSizeProperty, &swapChainSize, &swapChainSizeSpecified); + } + } + + if (SUCCEEDED(result)) + { + result = win.As(&mSwapChainPanel); + } + + if (SUCCEEDED(result)) + { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds + // of the host. + // Scaling of the swapchain output needs to be handled by the + // host for swapchain panels even though the scaling mode setting + // DXGI_SCALING_STRETCH is configured on the swapchain. + if (swapChainSizeSpecified) + { + mClientRect = { 0, 0, swapChainSize.cx, swapChainSize.cy }; + + // Enable host swapchain scaling + mRequiresSwapChainScaling = true; + } + else + { + result = GetSwapChainPanelSize(mSwapChainPanel, &mClientRect); + } + } + + if (SUCCEEDED(result)) + { + mNewClientRect = mClientRect; + mClientRectChanged = false; + return registerForSizeChangeEvents(); + } + + return false; +} + +bool SwapChainPanelNativeWindow::registerForSizeChangeEvents() +{ + ComPtr sizeChangedHandler; + ComPtr frameworkElement; + HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&frameworkElement); + } + + if (SUCCEEDED(result)) + { + result = frameworkElement->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); + } + + if (SUCCEEDED(result)) + { + return true; + } + + return false; +} + +void SwapChainPanelNativeWindow::unregisterForSizeChangeEvents() +{ + ComPtr frameworkElement; + if (SUCCEEDED(mSwapChainPanel.As(&frameworkElement))) + { + (void)frameworkElement->remove_SizeChanged(mSizeChangedEventToken); + } + + mSizeChangedEventToken.value = 0; +} + +HRESULT SwapChainPanelNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) +{ + if (device == NULL || factory == NULL || swapChain == NULL || width == 0 || height == 0) + { + return E_INVALIDARG; + } + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; + swapChainDesc.Width = width; + swapChainDesc.Height = height; + swapChainDesc.Format = format; + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_BACK_BUFFER; + swapChainDesc.BufferCount = 2; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + + *swapChain = nullptr; + + ComPtr newSwapChain; + ComPtr swapChainPanelNative; + RECT currentPanelSize = {}; + + HRESULT result = factory->CreateSwapChainForComposition(device, &swapChainDesc, nullptr, newSwapChain.ReleaseAndGetAddressOf()); + + if (SUCCEEDED(result)) + { + result = mSwapChainPanel.As(&swapChainPanelNative); + } + + if (SUCCEEDED(result)) + { + result = swapChainPanelNative->SetSwapChain(newSwapChain.Get()); + } + + if (SUCCEEDED(result)) + { + // The swapchain panel host requires an instance of the swapchain set on the SwapChainPanel + // to perform the runtime-scale behavior. This swapchain is cached here because there are + // no methods for retreiving the currently configured on from ISwapChainPanelNative. + mSwapChain = newSwapChain; + result = newSwapChain.CopyTo(swapChain); + } + + // If the host is responsible for scaling the output of the swapchain, then + // scale it now before returning an instance to the caller. This is done by + // first reading the current size of the swapchain panel, then scaling + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + result = GetSwapChainPanelSize(mSwapChainPanel, ¤tPanelSize); + } + + // Scale the swapchain to fit inside the contents of the panel. + if (SUCCEEDED(result) && mRequiresSwapChainScaling) + { + SIZE currentSize = { currentPanelSize.right, currentPanelSize.bottom }; + result = scaleSwapChain(currentSize); + } + + if (SUCCEEDED(result)) + { + // If automatic swapchain resize behaviors have been disabled, then + // unregister for the resize change events. + if (mSupportsSwapChainResize == false) + { + unregisterForSizeChangeEvents(); + } + } + + return result; +} + +HRESULT SwapChainPanelNativeWindow::scaleSwapChain(const SIZE &newSize) +{ + ABI::Windows::Foundation::Size renderScale = { (float)newSize.cx/(float)mClientRect.right, (float)newSize.cy/(float)mClientRect.bottom }; + // Setup a scale matrix for the swap chain + DXGI_MATRIX_3X2_F scaleMatrix = {}; + scaleMatrix._11 = renderScale.Width; + scaleMatrix._22 = renderScale.Height; + + ComPtr swapChain2; + HRESULT result = mSwapChain.As(&swapChain2); + if (SUCCEEDED(result)) + { + result = swapChain2->SetMatrixTransform(&scaleMatrix); + } + + return result; +} + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize) +{ + ComPtr uiElement; + ABI::Windows::Foundation::Size renderSize = { 0, 0 }; + HRESULT result = swapChainPanel.As(&uiElement); + if (SUCCEEDED(result)) + { + result = uiElement->get_RenderSize(&renderSize); + } + + if (SUCCEEDED(result)) + { + *windowSize = { 0, 0, lround(renderSize.Width), lround(renderSize.Height) }; + } + + return result; +} +} diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h new file mode 100644 index 0000000000..5bbf274e64 --- /dev/null +++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// SwapChainPanelNativeWindow.h: NativeWindow for managing ISwapChainPanel native window types. + +#ifndef COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ +#define COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ + +#include "common/winrt/InspectableNativeWindow.h" + +namespace rx +{ +class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this +{ + public: + ~SwapChainPanelNativeWindow(); + + bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + HRESULT scaleSwapChain(const SIZE &newSize); + + private: + ComPtr mSwapChainPanel; + ComPtr> mPropertyMap; + ComPtr mSwapChain; +}; + +[uuid(8ACBD974-8187-4508-AD80-AEC77F93CF36)] +class SwapChainPanelSizeChangedHandler : + public Microsoft::WRL::RuntimeClass, ABI::Windows::UI::Xaml::ISizeChangedEventHandler> +{ + public: + SwapChainPanelSizeChangedHandler() { } + HRESULT RuntimeClassInitialize(std::shared_ptr host) + { + if (!host) + { + return E_INVALIDARG; + } + + mHost = host; + return S_OK; + } + + // ISizeChangedEventHandler + IFACEMETHOD(Invoke)(IInspectable *sender, ABI::Windows::UI::Xaml::ISizeChangedEventArgs *sizeChangedEventArgs) + { + std::shared_ptr host = mHost.lock(); + if (host) + { + // The size of the ISwapChainPanel control is returned in DIPs. + // We are keeping these in dips because the swapchain created for composition + // also uses dip units. This keeps dimensions, viewports, etc in the same unit. + // XAML Clients of the ISwapChainPanel are required to use dips to define their + // layout sizes as well. + ABI::Windows::Foundation::Size newSize; + HRESULT result = sizeChangedEventArgs->get_NewSize(&newSize); + if (SUCCEEDED(result)) + { + SIZE windowSize = { lround(newSize.Width), lround(newSize.Height) }; + host->setNewClientSize(windowSize); + } + } + + return S_OK; + } + + private: + std::weak_ptr mHost; +}; + +HRESULT GetSwapChainPanelSize(const ComPtr &swapChainPanel, RECT *windowSize); +} +#endif // COMMON_WINRT_SWAPCHAINPANELNATIVEWINDOW_H_ diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h index 040b25c6a2..eec0d5e5f0 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveHandlerBase.h @@ -29,7 +29,8 @@ class DirectiveHandler // Handle pragma of form: #pragma name[(value)] virtual void handlePragma(const SourceLocation &loc, const std::string &name, - const std::string &value) = 0; + const std::string &value, + bool stdgl) = 0; virtual void handleExtension(const SourceLocation &loc, const std::string &name, diff --git a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp index 6434d5cb5c..7803ee845a 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/DirectiveParser.cpp @@ -38,19 +38,19 @@ enum DirectiveType DirectiveType getDirective(const pp::Token *token) { - static const std::string kDirectiveDefine("define"); - static const std::string kDirectiveUndef("undef"); - static const std::string kDirectiveIf("if"); - static const std::string kDirectiveIfdef("ifdef"); - static const std::string kDirectiveIfndef("ifndef"); - static const std::string kDirectiveElse("else"); - static const std::string kDirectiveElif("elif"); - static const std::string kDirectiveEndif("endif"); - static const std::string kDirectiveError("error"); - static const std::string kDirectivePragma("pragma"); - static const std::string kDirectiveExtension("extension"); - static const std::string kDirectiveVersion("version"); - static const std::string kDirectiveLine("line"); + const char kDirectiveDefine[] = "define"; + const char kDirectiveUndef[] = "undef"; + const char kDirectiveIf[] = "if"; + const char kDirectiveIfdef[] = "ifdef"; + const char kDirectiveIfndef[] = "ifndef"; + const char kDirectiveElse[] = "else"; + const char kDirectiveElif[] = "elif"; + const char kDirectiveEndif[] = "endif"; + const char kDirectiveError[] = "error"; + const char kDirectivePragma[] = "pragma"; + const char kDirectiveExtension[] = "extension"; + const char kDirectiveVersion[] = "version"; + const char kDirectiveLine[] = "line"; if (token->type != pp::Token::IDENTIFIER) return DIRECTIVE_NONE; @@ -155,7 +155,7 @@ class DefinedParser : public Lexer protected: virtual void lex(Token *token) { - static const std::string kDefined("defined"); + const char kDefined[] = "defined"; mLexer->lex(token); if (token->type != Token::IDENTIFIER) @@ -592,6 +592,11 @@ void DirectiveParser::parsePragma(Token *token) int state = PRAGMA_NAME; mTokenizer->lex(token); + bool stdgl = token->text == "STDGL"; + if (stdgl) + { + mTokenizer->lex(token); + } while ((token->type != '\n') && (token->type != Token::LAST)) { switch(state++) @@ -627,7 +632,7 @@ void DirectiveParser::parsePragma(Token *token) } else if (state > PRAGMA_NAME) // Do not notify for empty pragma. { - mDirectiveHandler->handlePragma(token->location, name, value); + mDirectiveHandler->handlePragma(token->location, name, value, stdgl); } } diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp index d7e0c83465..69e2f39069 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.cpp @@ -194,8 +194,8 @@ bool MacroExpander::expandMacro(const Macro ¯o, if (macro.predefined) { - static const std::string kLine = "__LINE__"; - static const std::string kFile = "__FILE__"; + const char kLine[] = "__LINE__"; + const char kFile[] = "__FILE__"; assert(replacements->size() == 1); Token& repl = replacements->front(); diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp index 368cd2ae4a..5c62a64d10 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.cpp @@ -29,24 +29,27 @@ bool IsWebGLBasedSpec(ShShaderSpec spec) { - return spec == SH_WEBGL_SPEC || spec == SH_CSS_SHADERS_SPEC; + return (spec == SH_WEBGL_SPEC || + spec == SH_CSS_SHADERS_SPEC || + spec == SH_WEBGL2_SPEC); } size_t GetGlobalMaxTokenSize(ShShaderSpec spec) { // WebGL defines a max token legnth of 256, while ES2 leaves max token // size undefined. ES3 defines a max size of 1024 characters. - if (IsWebGLBasedSpec(spec)) + switch (spec) { + case SH_WEBGL_SPEC: + case SH_CSS_SHADERS_SPEC: return 256; - } - else - { + default: return 1024; } } namespace { + class TScopedPoolAllocator { public: @@ -82,6 +85,24 @@ class TScopedSymbolTableLevel private: TSymbolTable* mTable; }; + +int MapSpecToShaderVersion(ShShaderSpec spec) +{ + switch (spec) + { + case SH_GLES2_SPEC: + case SH_WEBGL_SPEC: + case SH_CSS_SHADERS_SPEC: + return 100; + case SH_GLES3_SPEC: + case SH_WEBGL2_SPEC: + return 300; + default: + UNREACHABLE(); + return 0; + } +} + } // namespace TShHandleBase::TShHandleBase() @@ -178,9 +199,21 @@ bool TCompiler::compile(const char* const shaderStrings[], (parseContext.treeRoot != NULL); shaderVersion = parseContext.getShaderVersion(); + if (success && MapSpecToShaderVersion(shaderSpec) < shaderVersion) + { + infoSink.info.prefix(EPrefixError); + infoSink.info << "unsupported shader version"; + success = false; + } if (success) { + mPragma = parseContext.pragma(); + if (mPragma.stdgl.invariantAll) + { + symbolTable.setGlobalInvariant(); + } + TIntermNode* root = parseContext.treeRoot; success = intermediate.postProcess(root); @@ -360,7 +393,8 @@ void TCompiler::setResourceString() << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset - << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset; + << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset + << ":NV_draw_buffers:" << compileResources.NV_draw_buffers; builtInResourcesString = strstream.str(); } @@ -377,7 +411,6 @@ void TCompiler::clearResults() uniforms.clear(); expandedUniforms.clear(); varyings.clear(); - expandedVaryings.clear(); interfaceBlocks.clear(); builtInFunctionEmulator.Cleanup(); @@ -507,13 +540,12 @@ void TCompiler::collectVariables(TIntermNode* root) &uniforms, &varyings, &interfaceBlocks, - hashFunction); + hashFunction, + symbolTable); root->traverse(&collect); - // For backwards compatiblity with ShGetVariableInfo, expand struct - // uniforms and varyings into separate variables for each field. - sh::ExpandVariables(uniforms, &expandedUniforms); - sh::ExpandVariables(varyings, &expandedVaryings); + // This is for enforcePackingRestriction(). + sh::ExpandUniforms(uniforms, &expandedUniforms); } bool TCompiler::enforcePackingRestrictions() @@ -581,3 +613,10 @@ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const { return builtInFunctionEmulator; } + +void TCompiler::writePragma() +{ + TInfoSinkBase &sink = infoSink.obj; + if (mPragma.stdgl.invariantAll) + sink << "#pragma STDGL invariant(all)\n"; +} diff --git a/src/3rdparty/angle/src/compiler/translator/Compiler.h b/src/3rdparty/angle/src/compiler/translator/Compiler.h index ca0c157884..b6c9d13ed0 100644 --- a/src/3rdparty/angle/src/compiler/translator/Compiler.h +++ b/src/3rdparty/angle/src/compiler/translator/Compiler.h @@ -18,6 +18,7 @@ #include "compiler/translator/ExtensionBehavior.h" #include "compiler/translator/HashNames.h" #include "compiler/translator/InfoSink.h" +#include "compiler/translator/Pragma.h" #include "compiler/translator/SymbolTable.h" #include "compiler/translator/VariableInfo.h" #include "third_party/compiler/ArrayBoundsClamper.h" @@ -71,9 +72,7 @@ class TCompiler : public TShHandleBase const std::vector &getAttributes() const { return attributes; } const std::vector &getOutputVariables() const { return outputVariables; } const std::vector &getUniforms() const { return uniforms; } - const std::vector &getExpandedUniforms() const { return expandedUniforms; } const std::vector &getVaryings() const { return varyings; } - const std::vector &getExpandedVaryings() const { return expandedVaryings; } const std::vector &getInterfaceBlocks() const { return interfaceBlocks; } ShHashFunction64 getHashFunction() const { return hashFunction; } @@ -81,7 +80,7 @@ class TCompiler : public TShHandleBase TSymbolTable& getSymbolTable() { return symbolTable; } ShShaderSpec getShaderSpec() const { return shaderSpec; } ShShaderOutput getOutputType() const { return outputType; } - std::string getBuiltInResourcesString() const { return builtInResourcesString; } + const std::string &getBuiltInResourcesString() const { return builtInResourcesString; } // Get the resources set by InitBuiltInSymbolTable const ShBuiltInResources& getResources() const; @@ -131,6 +130,8 @@ class TCompiler : public TShHandleBase bool limitExpressionComplexity(TIntermNode* root); // Get built-in extensions with default behavior. const TExtensionBehavior& getExtensionBehavior() const; + const TPragma& getPragma() const { return mPragma; } + void writePragma(); const ArrayBoundsClamper& getArrayBoundsClamper() const; ShArrayIndexClampingStrategy getArrayIndexClampingStrategy() const; @@ -141,7 +142,6 @@ class TCompiler : public TShHandleBase std::vector uniforms; std::vector expandedUniforms; std::vector varyings; - std::vector expandedVaryings; std::vector interfaceBlocks; private: @@ -174,6 +174,8 @@ class TCompiler : public TShHandleBase // name hashing. ShHashFunction64 hashFunction; NameMap nameMap; + + TPragma mPragma; }; // diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp index 334eb0bfa8..f98d32b2b7 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.cpp @@ -14,6 +14,9 @@ namespace sh { + +// Detect Loop Discontinuity + bool DetectLoopDiscontinuity::traverse(TIntermNode *node) { mLoopDepth = 0; @@ -74,6 +77,55 @@ bool containsLoopDiscontinuity(TIntermNode *node) return detectLoopDiscontinuity.traverse(node); } +// Detect Any Loop + +bool DetectAnyLoop::traverse(TIntermNode *node) +{ + mHasLoop = false; + node->traverse(this); + return mHasLoop; +} + +bool DetectAnyLoop::visitLoop(Visit visit, TIntermLoop *loop) +{ + mHasLoop = true; + return false; +} + +// The following definitions stop all traversal when we have found a loop +bool DetectAnyLoop::visitBinary(Visit, TIntermBinary *) +{ + return !mHasLoop; +} + +bool DetectAnyLoop::visitUnary(Visit, TIntermUnary *) +{ + return !mHasLoop; +} + +bool DetectAnyLoop::visitSelection(Visit, TIntermSelection *) +{ + return !mHasLoop; +} + +bool DetectAnyLoop::visitAggregate(Visit, TIntermAggregate *) +{ + return !mHasLoop; +} + +bool DetectAnyLoop::visitBranch(Visit, TIntermBranch *) +{ + return !mHasLoop; +} + +bool containsAnyLoop(TIntermNode *node) +{ + DetectAnyLoop detectAnyLoop; + return detectAnyLoop.traverse(node); +} + +// Detect Gradient Operation + bool DetectGradientOperation::traverse(TIntermNode *node) { mGradientOperation = false; diff --git a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h index 35d66cbc2e..67e37be398 100644 --- a/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h +++ b/src/3rdparty/angle/src/compiler/translator/DetectDiscontinuity.h @@ -32,6 +32,25 @@ class DetectLoopDiscontinuity : public TIntermTraverser bool containsLoopDiscontinuity(TIntermNode *node); +// Checks for the existence of any loop +class DetectAnyLoop : public TIntermTraverser +{ +public: + bool traverse(TIntermNode *node); + +protected: + bool visitBinary(Visit, TIntermBinary *); + bool visitUnary(Visit, TIntermUnary *); + bool visitSelection(Visit, TIntermSelection *); + bool visitAggregate(Visit, TIntermAggregate *); + bool visitLoop(Visit, TIntermLoop *); + bool visitBranch(Visit, TIntermBranch *); + + bool mHasLoop; +}; + +bool containsAnyLoop(TIntermNode *node); + // Checks for intrinsic functions which compute gradients class DetectGradientOperation : public TIntermTraverser { diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp index 59d2835f7b..f67a03aa93 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.cpp @@ -13,10 +13,10 @@ static TBehavior getBehavior(const std::string& str) { - static const std::string kRequire("require"); - static const std::string kEnable("enable"); - static const std::string kDisable("disable"); - static const std::string kWarn("warn"); + const char kRequire[] = "require"; + const char kEnable[] = "enable"; + const char kDisable[] = "disable"; + const char kWarn[] = "warn"; if (str == kRequire) return EBhRequire; else if (str == kEnable) return EBhEnable; @@ -46,50 +46,61 @@ void TDirectiveHandler::handleError(const pp::SourceLocation& loc, void TDirectiveHandler::handlePragma(const pp::SourceLocation& loc, const std::string& name, - const std::string& value) + const std::string& value, + bool stdgl) { - static const std::string kSTDGL("STDGL"); - static const std::string kOptimize("optimize"); - static const std::string kDebug("debug"); - static const std::string kOn("on"); - static const std::string kOff("off"); + if (stdgl) + { + const char kInvariant[] = "invariant"; + const char kAll[] = "all"; - bool invalidValue = false; - if (name == kSTDGL) - { + if (name == kInvariant && value == kAll) + mPragma.stdgl.invariantAll = true; // The STDGL pragma is used to reserve pragmas for use by future - // revisions of GLSL. Ignore it. + // revisions of GLSL. Do not generate an error on unexpected + // name and value. return; } - else if (name == kOptimize) - { - if (value == kOn) mPragma.optimize = true; - else if (value == kOff) mPragma.optimize = false; - else invalidValue = true; - } - else if (name == kDebug) - { - if (value == kOn) mPragma.debug = true; - else if (value == kOff) mPragma.debug = false; - else invalidValue = true; - } else { - mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); - return; - } + const char kOptimize[] = "optimize"; + const char kDebug[] = "debug"; + const char kOn[] = "on"; + const char kOff[] = "off"; - if (invalidValue) - mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, - "invalid pragma value", value, - "'on' or 'off' expected"); + bool invalidValue = false; + if (name == kOptimize) + { + if (value == kOn) mPragma.optimize = true; + else if (value == kOff) mPragma.optimize = false; + else invalidValue = true; + } + else if (name == kDebug) + { + if (value == kOn) mPragma.debug = true; + else if (value == kOff) mPragma.debug = false; + else invalidValue = true; + } + else + { + mDiagnostics.report(pp::Diagnostics::PP_UNRECOGNIZED_PRAGMA, loc, name); + return; + } + + if (invalidValue) + { + mDiagnostics.writeInfo(pp::Diagnostics::PP_ERROR, loc, + "invalid pragma value", value, + "'on' or 'off' expected"); + } + } } void TDirectiveHandler::handleExtension(const pp::SourceLocation& loc, const std::string& name, const std::string& behavior) { - static const std::string kExtAll("all"); + const char kExtAll[] = "all"; TBehavior behaviorVal = getBehavior(behavior); if (behaviorVal == EBhUndefined) diff --git a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h index 69418c277a..0433c3bf89 100644 --- a/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h +++ b/src/3rdparty/angle/src/compiler/translator/DirectiveHandler.h @@ -29,7 +29,8 @@ class TDirectiveHandler : public pp::DirectiveHandler virtual void handlePragma(const pp::SourceLocation& loc, const std::string& name, - const std::string& value); + const std::string& value, + bool stdgl); virtual void handleExtension(const pp::SourceLocation& loc, const std::string& name, diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp index b155545ad2..aa0f31d170 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.cpp @@ -133,6 +133,14 @@ bool CompareStructure(const TType &leftNodeType, // //////////////////////////////////////////////////////////////// +void TIntermTyped::setTypePreservePrecision(const TType &t) +{ + TPrecision precision = getPrecision(); + mType = t; + ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined); + mType.setPrecision(precision); +} + #define REPLACE_IF_IS(node, type, original, replacement) \ if (node == original) { \ node = static_cast(replacement); \ @@ -237,6 +245,52 @@ void TIntermAggregate::enqueueChildren(std::queue *nodeQueue) con } } +void TIntermAggregate::setPrecisionFromChildren() +{ + if (getBasicType() == EbtBool) + { + mType.setPrecision(EbpUndefined); + return; + } + + TPrecision precision = EbpUndefined; + TIntermSequence::iterator childIter = mSequence.begin(); + while (childIter != mSequence.end()) + { + TIntermTyped *typed = (*childIter)->getAsTyped(); + if (typed) + precision = GetHigherPrecision(typed->getPrecision(), precision); + ++childIter; + } + mType.setPrecision(precision); +} + +void TIntermAggregate::setBuiltInFunctionPrecision() +{ + // All built-ins returning bool should be handled as ops, not functions. + ASSERT(getBasicType() != EbtBool); + + TPrecision precision = EbpUndefined; + TIntermSequence::iterator childIter = mSequence.begin(); + while (childIter != mSequence.end()) + { + TIntermTyped *typed = (*childIter)->getAsTyped(); + // ESSL spec section 8: texture functions get their precision from the sampler. + if (typed && IsSampler(typed->getBasicType())) + { + precision = typed->getPrecision(); + break; + } + ++childIter; + } + // ESSL 3.0 spec section 8: textureSize always gets highp precision. + // All other functions that take a sampler are assumed to be texture functions. + if (mName.find("textureSize") == 0) + mType.setPrecision(EbpHigh); + else + mType.setPrecision(precision); +} + bool TIntermSelection::replaceChildNode( TIntermNode *original, TIntermNode *replacement) { @@ -336,6 +390,7 @@ bool TIntermUnary::promote(TInfoSink &) return false; break; case EOpNegative: + case EOpPositive: case EOpPostIncrement: case EOpPostDecrement: case EOpPreIncrement: @@ -1068,6 +1123,27 @@ TIntermTyped *TIntermConstantUnion::fold( } break; + case EOpPositive: + switch (getType().getBasicType()) + { + case EbtFloat: + tempConstArray[i].setFConst(unionArray[i].getFConst()); + break; + case EbtInt: + tempConstArray[i].setIConst(unionArray[i].getIConst()); + break; + case EbtUInt: + tempConstArray[i].setUConst(static_cast( + static_cast(unionArray[i].getUConst()))); + break; + default: + infoSink.info.message( + EPrefixInternalError, getLine(), + "Unary operation not folded into constant"); + return NULL; + } + break; + case EOpLogicalNot: // this code is written for possible future use, // will not get executed currently diff --git a/src/3rdparty/angle/src/compiler/translator/IntermNode.h b/src/3rdparty/angle/src/compiler/translator/IntermNode.h index ec440da010..32c70f4671 100644 --- a/src/3rdparty/angle/src/compiler/translator/IntermNode.h +++ b/src/3rdparty/angle/src/compiler/translator/IntermNode.h @@ -45,6 +45,7 @@ enum TOperator // EOpNegative, + EOpPositive, EOpLogicalNot, EOpVectorLogicalNot, @@ -265,6 +266,7 @@ class TIntermTyped : public TIntermNode virtual bool hasSideEffects() const = 0; void setType(const TType &t) { mType = t; } + void setTypePreservePrecision(const TType &t); const TType &getType() const { return mType; } TType *getTypePointer() { return &mType; } @@ -613,6 +615,9 @@ class TIntermAggregate : public TIntermOperator virtual void enqueueChildren(std::queue *nodeQueue) const; + void setPrecisionFromChildren(); + void setBuiltInFunctionPrecision(); + protected: TIntermAggregate(const TIntermAggregate &); // disallow copy constructor TIntermAggregate &operator=(const TIntermAggregate &); // disallow assignment operator diff --git a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp index ef4f83307c..e558683c55 100644 --- a/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp +++ b/src/3rdparty/angle/src/compiler/translator/Intermediate.cpp @@ -198,6 +198,7 @@ TIntermTyped *TIntermediate::addUnaryMath( case EOpPostDecrement: case EOpPreDecrement: case EOpNegative: + case EOpPositive: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) { diff --git a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp index 6d07cccc04..ed590967b1 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputGLSLBase.cpp @@ -395,6 +395,7 @@ bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node) switch (node->getOp()) { case EOpNegative: preString = "(-"; break; + case EOpPositive: preString = "(+"; break; case EOpVectorLogicalNot: preString = "not("; break; case EOpLogicalNot: preString = "(!"; break; @@ -574,7 +575,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) // Function declaration. ASSERT(visit == PreVisit); writeVariableType(node->getType()); - out << " " << hashName(node->getName()); + out << " " << hashFunctionName(node->getName()); out << "("; writeFunctionParameters(*(node->getSequence())); @@ -649,17 +650,18 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) mDeclaringVariables = false; } break; - case EOpInvariantDeclaration: { - // Invariant declaration. - ASSERT(visit == PreVisit); + case EOpInvariantDeclaration: + // Invariant declaration. + ASSERT(visit == PreVisit); + { const TIntermSequence *sequence = node->getSequence(); ASSERT(sequence && sequence->size() == 1); const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode(); ASSERT(symbol); - out << "invariant " << symbol->getSymbol() << ";"; - visitChildren = false; - break; + out << "invariant " << hashVariableName(symbol->getSymbol()); } + visitChildren = false; + break; case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break; @@ -741,7 +743,7 @@ bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node) writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction); break; case EOpComma: - writeTriplet(visit, NULL, ", ", NULL); + writeTriplet(visit, "(", ", ", ")"); break; case EOpMod: diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp index a5ea71599d..30bbbff0f5 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.cpp @@ -135,6 +135,7 @@ OutputHLSL::OutputHLSL(TParseContext &context, TranslatorHLSL *parentTranslator) mUniqueIndex = 0; mContainsLoopDiscontinuity = false; + mContainsAnyLoop = false; mOutputLod0Function = false; mInsideDiscontinuousLoop = false; mNestedLoopDepth = 0; @@ -172,6 +173,7 @@ OutputHLSL::~OutputHLSL() void OutputHLSL::output() { mContainsLoopDiscontinuity = mContext.shaderType == GL_FRAGMENT_SHADER && containsLoopDiscontinuity(mContext.treeRoot); + mContainsAnyLoop = containsAnyLoop(mContext.treeRoot); const std::vector &flaggedStructs = FlagStd140ValueStructs(mContext.treeRoot); makeFlaggedStructMaps(flaggedStructs); @@ -320,14 +322,22 @@ void OutputHLSL::header() if (mUsesDiscardRewriting) { - out << "#define ANGLE_USES_DISCARD_REWRITING" << "\n"; + out << "#define ANGLE_USES_DISCARD_REWRITING\n"; } if (mUsesNestedBreak) { - out << "#define ANGLE_USES_NESTED_BREAK" << "\n"; + out << "#define ANGLE_USES_NESTED_BREAK\n"; } + out << "#ifdef ANGLE_ENABLE_LOOP_FLATTEN\n" + "#define LOOP [loop]\n" + "#define FLATTEN [flatten]\n" + "#else\n" + "#define LOOP\n" + "#define FLATTEN\n" + "#endif\n"; + if (mContext.shaderType == GL_FRAGMENT_SHADER) { TExtensionBehavior::const_iterator iter = mContext.extensionBehavior().find("GL_EXT_draw_buffers"); @@ -1747,6 +1757,7 @@ bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) switch (node->getOp()) { case EOpNegative: outputTriplet(visit, "(-", "", ")"); break; + case EOpPositive: outputTriplet(visit, "(+", "", ")"); break; case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break; case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break; case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break; @@ -1860,15 +1871,20 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration { - if (!mInsideFunction) - { - out << "static "; - } - - out << TypeString(variable->getType()) + " "; - for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); sit++) { + if (isSingleStatement(*sit)) + { + mUnfoldShortCircuit->traverse(*sit); + } + + if (!mInsideFunction) + { + out << "static "; + } + + out << TypeString(variable->getType()) + " "; + TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); if (symbol) @@ -1884,7 +1900,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) if (*sit != sequence->back()) { - out << ", "; + out << ";\n"; } } } @@ -1925,7 +1941,7 @@ bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) case EOpPrototype: if (visit == PreVisit) { - out << TypeString(node->getType()) << " " << Decorate(node->getName()) << (mOutputLod0Function ? "Lod0(" : "("); + out << TypeString(node->getType()) << " " << Decorate(TFunction::unmangleName(node->getName())) << (mOutputLod0Function ? "Lod0(" : "("); TIntermSequence *arguments = node->getSequence(); @@ -2287,6 +2303,15 @@ bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) { mUnfoldShortCircuit->traverse(node->getCondition()); + // D3D errors when there is a gradient operation in a loop in an unflattened if + // however flattening all the ifs in branch heavy shaders made D3D error too. + // As a temporary workaround we flatten the ifs only if there is at least a loop + // present somewhere in the shader. + if (mContext.shaderType == GL_FRAGMENT_SHADER && mContainsAnyLoop) + { + out << "FLATTEN "; + } + out << "if ("; node->getCondition()->traverse(this); @@ -2367,14 +2392,14 @@ bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) if (node->getType() == ELoopDoWhile) { - out << "{do\n"; + out << "{LOOP do\n"; outputLineDirective(node->getLine().first_line); out << "{\n"; } else { - out << "{for("; + out << "{LOOP for("; if (node->getInit()) { @@ -2503,6 +2528,12 @@ bool OutputHLSL::isSingleStatement(TIntermNode *node) { return false; } + else if (aggregate->getOp() == EOpDeclaration) + { + // Declaring multiple comma-separated variables must be considered multiple statements + // because each individual declaration has side effects which are visible in the next. + return false; + } else { for (TIntermSequence::iterator sit = aggregate->getSequence()->begin(); sit != aggregate->getSequence()->end(); sit++) @@ -2675,7 +2706,7 @@ bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node) // for(int index = initial; index < clampedLimit; index += increment) - out << "for("; + out << "LOOP for("; index->traverse(this); out << " = "; out << initial; diff --git a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h index bec02479bb..5525e6eaa6 100644 --- a/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/OutputHLSL.h @@ -144,6 +144,7 @@ class OutputHLSL : public TIntermTraverser int mUniqueIndex; // For creating unique names bool mContainsLoopDiscontinuity; + bool mContainsAnyLoop; bool mOutputLod0Function; bool mInsideDiscontinuousLoop; int mNestedLoopDepth; diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp index ff0a49667c..37969b5468 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.cpp @@ -1004,12 +1004,12 @@ void TParseContext::handleExtensionDirective(const TSourceLoc& loc, const char* directiveHandler.handleExtension(srcLoc, extName, behavior); } -void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value) +void TParseContext::handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl) { pp::SourceLocation srcLoc; srcLoc.file = loc.first_file; srcLoc.line = loc.first_line; - directiveHandler.handlePragma(srcLoc, name, value); + directiveHandler.handlePragma(srcLoc, name, value, stdgl); } ///////////////////////////////////////////////////////////////////////////////// @@ -1364,11 +1364,18 @@ TIntermAggregate* TParseContext::parseInvariantDeclaration(const TSourceLoc &inv { error(identifierLoc, "undeclared identifier declared as invariant", identifier->c_str()); recover(); - return NULL; } else { + const TString kGlFrontFacing("gl_FrontFacing"); + if (*identifier == kGlFrontFacing) + { + error(identifierLoc, "identifier should not be declared as invariant", identifier->c_str()); + recover(); + return NULL; + } + symbolTable.addInvariantVarying(*identifier); const TVariable *variable = getNamedVariable(identifierLoc, identifier, symbol); ASSERT(variable); const TType &type = variable->getType(); diff --git a/src/3rdparty/angle/src/compiler/translator/ParseContext.h b/src/3rdparty/angle/src/compiler/translator/ParseContext.h index 1f4cbdeba9..414c475cbb 100644 --- a/src/3rdparty/angle/src/compiler/translator/ParseContext.h +++ b/src/3rdparty/angle/src/compiler/translator/ParseContext.h @@ -116,7 +116,7 @@ struct TParseContext { bool supportsExtension(const char* extension); bool isExtensionEnabled(const char* extension) const; void handleExtensionDirective(const TSourceLoc& loc, const char* extName, const char* behavior); - void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value); + void handlePragmaDirective(const TSourceLoc& loc, const char* name, const char* value, bool stdgl); bool containsSampler(TType& type); bool areAllChildConst(TIntermAggregate* aggrNode); diff --git a/src/3rdparty/angle/src/compiler/translator/Pragma.h b/src/3rdparty/angle/src/compiler/translator/Pragma.h index 2f744123b8..4a930a2962 100644 --- a/src/3rdparty/angle/src/compiler/translator/Pragma.h +++ b/src/3rdparty/angle/src/compiler/translator/Pragma.h @@ -7,13 +7,23 @@ #ifndef COMPILER_PRAGMA_H_ #define COMPILER_PRAGMA_H_ -struct TPragma { +struct TPragma +{ + struct STDGL + { + STDGL() : invariantAll(false) { } + + bool invariantAll; + }; + + // By default optimization is turned on and debug is turned off. TPragma() : optimize(true), debug(false) { } TPragma(bool o, bool d) : optimize(o), debug(d) { } bool optimize; bool debug; + STDGL stdgl; }; #endif // COMPILER_PRAGMA_H_ diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp index 20ce71605c..0d6a1d64cf 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderLang.cpp @@ -37,72 +37,6 @@ bool isInitialized = false; // and the shading language compiler. // -static bool CheckVariableMaxLengths(const ShHandle handle, - size_t expectedValue) -{ - size_t activeUniformLimit = 0; - ShGetInfo(handle, SH_ACTIVE_UNIFORM_MAX_LENGTH, &activeUniformLimit); - size_t activeAttribLimit = 0; - ShGetInfo(handle, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &activeAttribLimit); - size_t varyingLimit = 0; - ShGetInfo(handle, SH_VARYING_MAX_LENGTH, &varyingLimit); - return (expectedValue == activeUniformLimit && - expectedValue == activeAttribLimit && - expectedValue == varyingLimit); -} - -bool CheckMappedNameMaxLength(const ShHandle handle, size_t expectedValue) -{ - size_t mappedNameMaxLength = 0; - ShGetInfo(handle, SH_MAPPED_NAME_MAX_LENGTH, &mappedNameMaxLength); - return (expectedValue == mappedNameMaxLength); -} - -template -const sh::ShaderVariable *ReturnVariable(const std::vector &infoList, int index) -{ - if (index < 0 || static_cast(index) >= infoList.size()) - { - return NULL; - } - - return &infoList[index]; -} - -const sh::ShaderVariable *GetVariable(const TCompiler *compiler, ShShaderInfo varType, int index) -{ - switch (varType) - { - case SH_ACTIVE_ATTRIBUTES: - return ReturnVariable(compiler->getAttributes(), index); - case SH_ACTIVE_UNIFORMS: - return ReturnVariable(compiler->getExpandedUniforms(), index); - case SH_VARYINGS: - return ReturnVariable(compiler->getExpandedVaryings(), index); - default: - UNREACHABLE(); - return NULL; - } -} - -ShPrecisionType ConvertPrecision(sh::GLenum precision) -{ - switch (precision) - { - case GL_HIGH_FLOAT: - case GL_HIGH_INT: - return SH_PRECISION_HIGHP; - case GL_MEDIUM_FLOAT: - case GL_MEDIUM_INT: - return SH_PRECISION_MEDIUMP; - case GL_LOW_FLOAT: - case GL_LOW_INT: - return SH_PRECISION_LOWP; - default: - return SH_PRECISION_UNDEFINED; - } -} - template const std::vector *GetVariableList(const TCompiler *compiler, ShaderVariableType variableType); @@ -150,32 +84,48 @@ const std::vector *GetShaderVariables(const ShHandle handle, ShaderVariabl return GetVariableList(compiler, variableType); } +TCompiler *GetCompilerFromHandle(ShHandle handle) +{ + if (!handle) + return NULL; + TShHandleBase *base = static_cast(handle); + return base->getAsCompiler(); } +TranslatorHLSL *GetTranslatorHLSLFromHandle(ShHandle handle) +{ + if (!handle) + return NULL; + TShHandleBase *base = static_cast(handle); + return base->getAsTranslatorHLSL(); +} + +} // namespace anonymous + // // Driver must call this first, once, before doing any other compiler operations. // Subsequent calls to this function are no-op. // -int ShInitialize() +bool ShInitialize() { if (!isInitialized) { isInitialized = InitProcess(); } - return isInitialized ? 1 : 0; + return isInitialized; } // // Cleanup symbol tables // -int ShFinalize() +bool ShFinalize() { if (isInitialized) { DetachProcess(); isInitialized = false; } - return 1; + return true; } // @@ -183,6 +133,9 @@ int ShFinalize() // void ShInitBuiltInResources(ShBuiltInResources* resources) { + // Make comparable. + memset(resources, 0, sizeof(*resources)); + // Constants. resources->MaxVertexAttribs = 8; resources->MaxVertexUniformVectors = 128; @@ -201,6 +154,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) resources->EXT_frag_depth = 0; resources->EXT_shader_texture_lod = 0; + resources->NV_draw_buffers = 0; + // Disable highp precision in fragment shader by default. resources->FragmentPrecisionHigh = 0; @@ -251,23 +206,13 @@ void ShDestruct(ShHandle handle) DeleteCompiler(base->getAsCompiler()); } -void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, char *outString) +const std::string &ShGetBuiltInResourcesString(const ShHandle handle) { - if (!handle || !outString) - { - return; - } - - TShHandleBase *base = static_cast(handle); - TCompiler *compiler = base->getAsCompiler(); - if (!compiler) - { - return; - } - - strncpy(outString, compiler->getBuiltInResourcesString().c_str(), outStringLen); - outString[outStringLen - 1] = '\0'; + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getBuiltInResourcesString(); } + // // Do an actual compile on the given strings. The result is left // in the given compile object. @@ -275,219 +220,62 @@ void ShGetBuiltInResourcesString(const ShHandle handle, size_t outStringLen, cha // Return: The return value of ShCompile is really boolean, indicating // success or failure. // -int ShCompile( +bool ShCompile( const ShHandle handle, - const char* const shaderStrings[], + const char *const shaderStrings[], size_t numStrings, int compileOptions) { - if (handle == 0) - return 0; + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); - TShHandleBase* base = reinterpret_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (compiler == 0) - return 0; - - bool success = compiler->compile(shaderStrings, numStrings, compileOptions); - return success ? 1 : 0; + return compiler->compile(shaderStrings, numStrings, compileOptions); } -void ShGetInfo(const ShHandle handle, ShShaderInfo pname, size_t* params) +int ShGetShaderVersion(const ShHandle handle) { - if (!handle || !params) - return; + TCompiler* compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getShaderVersion(); +} - TShHandleBase* base = static_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (!compiler) return; - - switch(pname) - { - case SH_INFO_LOG_LENGTH: - *params = compiler->getInfoSink().info.size() + 1; - break; - case SH_OBJECT_CODE_LENGTH: - *params = compiler->getInfoSink().obj.size() + 1; - break; - case SH_ACTIVE_UNIFORMS: - *params = compiler->getExpandedUniforms().size(); - break; - case SH_ACTIVE_UNIFORM_MAX_LENGTH: - *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - break; - case SH_ACTIVE_ATTRIBUTES: - *params = compiler->getAttributes().size(); - break; - case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: - *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - break; - case SH_VARYINGS: - *params = compiler->getExpandedVaryings().size(); - break; - case SH_VARYING_MAX_LENGTH: - *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - break; - case SH_MAPPED_NAME_MAX_LENGTH: - // Use longer length than MAX_SHORTENED_IDENTIFIER_SIZE to - // handle array and struct dereferences. - *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - break; - case SH_NAME_MAX_LENGTH: - *params = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - break; - case SH_HASHED_NAME_MAX_LENGTH: - if (compiler->getHashFunction() == NULL) { - *params = 0; - } else { - // 64 bits hashing output requires 16 bytes for hex - // representation. - const char HashedNamePrefix[] = HASHED_NAME_PREFIX; - (void)HashedNamePrefix; - *params = 16 + sizeof(HashedNamePrefix); - } - break; - case SH_HASHED_NAMES_COUNT: - *params = compiler->getNameMap().size(); - break; - case SH_SHADER_VERSION: - *params = compiler->getShaderVersion(); - break; - case SH_RESOURCES_STRING_LENGTH: - *params = compiler->getBuiltInResourcesString().length() + 1; - break; - case SH_OUTPUT_TYPE: - *params = compiler->getOutputType(); - break; - default: UNREACHABLE(); - } +ShShaderOutput ShGetShaderOutputType(const ShHandle handle) +{ + TCompiler* compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return compiler->getOutputType(); } // // Return any compiler log of messages for the application. // -void ShGetInfoLog(const ShHandle handle, char* infoLog) +const std::string &ShGetInfoLog(const ShHandle handle) { - if (!handle || !infoLog) - return; + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); - TShHandleBase* base = static_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (!compiler) return; - - TInfoSink& infoSink = compiler->getInfoSink(); - strcpy(infoLog, infoSink.info.c_str()); + TInfoSink &infoSink = compiler->getInfoSink(); + return infoSink.info.str(); } // // Return any object code. // -void ShGetObjectCode(const ShHandle handle, char* objCode) +const std::string &ShGetObjectCode(const ShHandle handle) { - if (!handle || !objCode) - return; + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); - TShHandleBase* base = static_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (!compiler) return; - - TInfoSink& infoSink = compiler->getInfoSink(); - strcpy(objCode, infoSink.obj.c_str()); + TInfoSink &infoSink = compiler->getInfoSink(); + return infoSink.obj.str(); } -void ShGetVariableInfo(const ShHandle handle, - ShShaderInfo varType, - int index, - size_t* length, - int* size, - sh::GLenum* type, - ShPrecisionType* precision, - int* staticUse, - char* name, - char* mappedName) +const std::map *ShGetNameHashingMap( + const ShHandle handle) { - if (!handle || !size || !type || !precision || !staticUse || !name) - return; - ASSERT((varType == SH_ACTIVE_ATTRIBUTES) || - (varType == SH_ACTIVE_UNIFORMS) || - (varType == SH_VARYINGS)); - - TShHandleBase* base = reinterpret_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (compiler == 0) - return; - - const sh::ShaderVariable *varInfo = GetVariable(compiler, varType, index); - if (!varInfo) - { - return; - } - - if (length) *length = varInfo->name.size(); - *size = varInfo->elementCount(); - *type = varInfo->type; - *precision = ConvertPrecision(varInfo->precision); - *staticUse = varInfo->staticUse ? 1 : 0; - - // This size must match that queried by - // SH_ACTIVE_UNIFORM_MAX_LENGTH, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, SH_VARYING_MAX_LENGTH - // in ShGetInfo, below. - size_t variableLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - ASSERT(CheckVariableMaxLengths(handle, variableLength)); - strncpy(name, varInfo->name.c_str(), variableLength); - name[variableLength - 1] = 0; - if (mappedName) - { - // This size must match that queried by - // SH_MAPPED_NAME_MAX_LENGTH in ShGetInfo, below. - size_t maxMappedNameLength = 1 + GetGlobalMaxTokenSize(compiler->getShaderSpec()); - ASSERT(CheckMappedNameMaxLength(handle, maxMappedNameLength)); - strncpy(mappedName, varInfo->mappedName.c_str(), maxMappedNameLength); - mappedName[maxMappedNameLength - 1] = 0; - } -} - -void ShGetNameHashingEntry(const ShHandle handle, - int index, - char* name, - char* hashedName) -{ - if (!handle || !name || !hashedName || index < 0) - return; - - TShHandleBase* base = static_cast(handle); - TCompiler* compiler = base->getAsCompiler(); - if (!compiler) return; - - const NameMap& nameMap = compiler->getNameMap(); - if (index >= static_cast(nameMap.size())) - return; - - NameMap::const_iterator it = nameMap.begin(); - for (int i = 0; i < index; ++i) - ++it; - - size_t len = it->first.length() + 1; - size_t max_len = 0; - ShGetInfo(handle, SH_NAME_MAX_LENGTH, &max_len); - if (len > max_len) { - ASSERT(false); - len = max_len; - } - strncpy(name, it->first.c_str(), len); - // To be on the safe side in case the source is longer than expected. - name[len - 1] = '\0'; - - len = it->second.length() + 1; - max_len = 0; - ShGetInfo(handle, SH_HASHED_NAME_MAX_LENGTH, &max_len); - if (len > max_len) { - ASSERT(false); - len = max_len; - } - strncpy(hashedName, it->second.c_str(), len); - // To be on the safe side in case the source is longer than expected. - hashedName[len - 1] = '\0'; + TCompiler *compiler = GetCompilerFromHandle(handle); + ASSERT(compiler); + return &(compiler->getNameMap()); } const std::vector *ShGetUniforms(const ShHandle handle) @@ -515,11 +303,11 @@ const std::vector *ShGetInterfaceBlocks(const ShHandle handl return GetShaderVariables(handle, SHADERVAR_INTERFACEBLOCK); } -int ShCheckVariablesWithinPackingLimits( - int maxVectors, ShVariableInfo* varInfoArray, size_t varInfoArraySize) +bool ShCheckVariablesWithinPackingLimits( + int maxVectors, ShVariableInfo *varInfoArray, size_t varInfoArraySize) { if (varInfoArraySize == 0) - return 1; + return true; ASSERT(varInfoArray); std::vector variables; for (size_t ii = 0; ii < varInfoArraySize; ++ii) @@ -528,24 +316,17 @@ int ShCheckVariablesWithinPackingLimits( variables.push_back(var); } VariablePacker packer; - return packer.CheckVariablesWithinPackingLimits(maxVectors, variables) ? 1 : 0; + return packer.CheckVariablesWithinPackingLimits(maxVectors, variables); } bool ShGetInterfaceBlockRegister(const ShHandle handle, - const char *interfaceBlockName, + const std::string &interfaceBlockName, unsigned int *indexOut) { - if (!handle || !interfaceBlockName || !indexOut) - { - return false; - } + ASSERT(indexOut); - TShHandleBase* base = static_cast(handle); - TranslatorHLSL* translator = base->getAsTranslatorHLSL(); - if (!translator) - { - return false; - } + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); if (!translator->hasInterfaceBlock(interfaceBlockName)) { @@ -557,20 +338,12 @@ bool ShGetInterfaceBlockRegister(const ShHandle handle, } bool ShGetUniformRegister(const ShHandle handle, - const char *uniformName, + const std::string &uniformName, unsigned int *indexOut) { - if (!handle || !uniformName || !indexOut) - { - return false; - } - - TShHandleBase* base = static_cast(handle); - TranslatorHLSL* translator = base->getAsTranslatorHLSL(); - if (!translator) - { - return false; - } + ASSERT(indexOut); + TranslatorHLSL *translator = GetTranslatorHLSLFromHandle(handle); + ASSERT(translator); if (!translator->hasUniform(uniformName)) { diff --git a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp index 822c558c9b..3098a7f0c9 100644 --- a/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ShaderVars.cpp @@ -9,6 +9,8 @@ #include +#include "compiler/translator/compilerdebug.h" + namespace sh { @@ -53,6 +55,126 @@ ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other) return *this; } +bool ShaderVariable::operator==(const ShaderVariable &other) const +{ + if (type != other.type || + precision != other.precision || + name != other.name || + mappedName != other.mappedName || + arraySize != other.arraySize || + staticUse != other.staticUse || + fields.size() != other.fields.size() || + structName != other.structName) + { + return false; + } + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (fields[ii] != other.fields[ii]) + return false; + } + return true; +} + +bool ShaderVariable::findInfoByMappedName( + const std::string &mappedFullName, + const ShaderVariable **leafVar, std::string *originalFullName) const +{ + ASSERT(leafVar && originalFullName); + // There are three cases: + // 1) the top variable is of struct type; + // 2) the top variable is an array; + // 3) otherwise. + size_t pos = mappedFullName.find_first_of(".["); + std::string topName; + + if (pos == std::string::npos) + { + // Case 3. + if (mappedFullName != this->mappedName) + return false; + *originalFullName = this->name; + *leafVar = this; + return true; + } + else + { + std::string topName = mappedFullName.substr(0, pos); + if (topName != this->mappedName) + return false; + std::string originalName = this->name; + std::string remaining; + if (mappedFullName[pos] == '[') + { + // Case 2. + size_t closePos = mappedFullName.find_first_of(']'); + if (closePos < pos || closePos == std::string::npos) + return false; + // Append '[index]'. + originalName += mappedFullName.substr(pos, closePos - pos + 1); + if (closePos + 1 == mappedFullName.size()) + { + *originalFullName = originalName; + *leafVar = this; + return true; + } + else + { + // In the form of 'a[0].b', so after ']', '.' is expected. + if (mappedFullName[closePos + 1] != '.') + return false; + remaining = mappedFullName.substr(closePos + 2); // Skip "]." + } + } + else + { + // Case 1. + remaining = mappedFullName.substr(pos + 1); // Skip "." + } + for (size_t ii = 0; ii < this->fields.size(); ++ii) + { + const ShaderVariable *fieldVar = NULL; + std::string originalFieldName; + bool found = fields[ii].findInfoByMappedName( + remaining, &fieldVar, &originalFieldName); + if (found) + { + *originalFullName = originalName + "." + originalFieldName; + *leafVar = fieldVar; + return true; + } + } + return false; + } +} + +bool ShaderVariable::isSameVariableAtLinkTime( + const ShaderVariable &other, bool matchPrecision) const +{ + if (type != other.type) + return false; + if (matchPrecision && precision != other.precision) + return false; + if (name != other.name) + return false; + ASSERT(mappedName == other.mappedName); + if (arraySize != other.arraySize) + return false; + if (fields.size() != other.fields.size()) + return false; + for (size_t ii = 0; ii < fields.size(); ++ii) + { + if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], + matchPrecision)) + { + return false; + } + } + if (structName != other.structName) + return false; + return true; +} + Uniform::Uniform() {} @@ -69,6 +191,16 @@ Uniform &Uniform::operator=(const Uniform &other) return *this; } +bool Uniform::operator==(const Uniform &other) const +{ + return ShaderVariable::operator==(other); +} + +bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const +{ + return ShaderVariable::isSameVariableAtLinkTime(other, true); +} + Attribute::Attribute() : location(-1) {} @@ -88,6 +220,12 @@ Attribute &Attribute::operator=(const Attribute &other) return *this; } +bool Attribute::operator==(const Attribute &other) const +{ + return (ShaderVariable::operator==(other) && + location == other.location); +} + InterfaceBlockField::InterfaceBlockField() : isRowMajorLayout(false) {} @@ -107,6 +245,19 @@ InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &o return *this; } +bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const +{ + return (ShaderVariable::operator==(other) && + isRowMajorLayout == other.isRowMajorLayout); +} + +bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime( + const InterfaceBlockField &other) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, true) && + isRowMajorLayout == other.isRowMajorLayout); +} + Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) @@ -129,6 +280,20 @@ Varying &Varying::operator=(const Varying &other) return *this; } +bool Varying::operator==(const Varying &other) const +{ + return (ShaderVariable::operator==(other) && + interpolation == other.interpolation && + isInvariant == other.isInvariant); +} + +bool Varying::isSameVaryingAtLinkTime(const Varying &other) const +{ + return (ShaderVariable::isSameVariableAtLinkTime(other, false) && + interpolation == other.interpolation && + isInvariant == other.isInvariant); +} + InterfaceBlock::InterfaceBlock() : arraySize(0), layout(BLOCKLAYOUT_PACKED), diff --git a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h index 6b0e0c0a03..9cd74218dc 100644 --- a/src/3rdparty/angle/src/compiler/translator/SymbolTable.h +++ b/src/3rdparty/angle/src/compiler/translator/SymbolTable.h @@ -31,6 +31,7 @@ // #include +#include #include "common/angleutils.h" #include "compiler/translator/InfoSink.h" @@ -299,19 +300,21 @@ class TSymbolTableLevel tLevel level; }; -enum ESymbolLevel -{ - COMMON_BUILTINS = 0, - ESSL1_BUILTINS = 1, - ESSL3_BUILTINS = 2, - LAST_BUILTIN_LEVEL = ESSL3_BUILTINS, - GLOBAL_LEVEL = 3 -}; +// Define ESymbolLevel as int rather than an enum since level can go +// above GLOBAL_LEVEL and cause atBuiltInLevel() to fail if the +// compiler optimizes the >= of the last element to ==. +typedef int ESymbolLevel; +const int COMMON_BUILTINS = 0; +const int ESSL1_BUILTINS = 1; +const int ESSL3_BUILTINS = 2; +const int LAST_BUILTIN_LEVEL = ESSL3_BUILTINS; +const int GLOBAL_LEVEL = 3; class TSymbolTable { public: TSymbolTable() + : mGlobalInvariant(false) { // The symbol table cannot be used until push() is called, but // the lack of an initial call to push() can be used to detect @@ -408,6 +411,25 @@ class TSymbolTable // for the specified TBasicType TPrecision getDefaultPrecision(TBasicType type) const; + // This records invariant varyings declared through + // "invariant varying_name;". + void addInvariantVarying(const TString &originalName) + { + mInvariantVaryings.insert(originalName); + } + // If this returns false, the varying could still be invariant + // if it is set as invariant during the varying variable + // declaration - this piece of information is stored in the + // variable's type, not here. + bool isVaryingInvariant(const TString &originalName) const + { + return (mGlobalInvariant || + mInvariantVaryings.count(originalName) > 0); + } + + void setGlobalInvariant() { mGlobalInvariant = true; } + bool getGlobalInvariant() const { return mGlobalInvariant; } + static int nextUniqueId() { return ++uniqueIdCounter; @@ -423,6 +445,9 @@ class TSymbolTable typedef TMap PrecisionStackLevel; std::vector< PrecisionStackLevel *> precisionStack; + std::set mInvariantVaryings; + bool mGlobalInvariant; + static int uniqueIdCounter; }; diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp index 5b99fea948..dcbf3cea1d 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorESSL.cpp @@ -16,6 +16,8 @@ TranslatorESSL::TranslatorESSL(sh::GLenum type, ShShaderSpec spec) void TranslatorESSL::translate(TIntermNode* root) { TInfoSinkBase& sink = getInfoSink().obj; + writePragma(); + // Write built-in extension behaviors. writeExtensionBehavior(); @@ -37,8 +39,13 @@ void TranslatorESSL::writeExtensionBehavior() { for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter) { if (iter->second != EBhUndefined) { - sink << "#extension " << iter->first << " : " - << getBehaviorString(iter->second) << "\n"; + if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") { + sink << "#extension GL_NV_draw_buffers : " + << getBehaviorString(iter->second) << "\n"; + } else { + sink << "#extension " << iter->first << " : " + << getBehaviorString(iter->second) << "\n"; + } } } } diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp index 4b2aecab33..6acbf7c5a8 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.cpp @@ -9,18 +9,6 @@ #include "compiler/translator/OutputGLSL.h" #include "compiler/translator/VersionGLSL.h" -static void writeVersion(sh::GLenum type, TIntermNode* root, - TInfoSinkBase& sink) { - TVersionGLSL versionGLSL(type); - root->traverse(&versionGLSL); - int version = versionGLSL.getVersion(); - // We need to write version directive only if it is greater than 110. - // If there is no version directive in the shader, 110 is implied. - if (version > 110) { - sink << "#version " << version << "\n"; - } -} - TranslatorGLSL::TranslatorGLSL(sh::GLenum type, ShShaderSpec spec) : TCompiler(type, spec, SH_GLSL_OUTPUT) { } @@ -29,7 +17,9 @@ void TranslatorGLSL::translate(TIntermNode* root) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. - writeVersion(getShaderType(), root, sink); + writeVersion(root); + + writePragma(); // Write extension behaviour as needed writeExtensionBehavior(); @@ -46,6 +36,20 @@ void TranslatorGLSL::translate(TIntermNode* root) { root->traverse(&outputGLSL); } +void TranslatorGLSL::writeVersion(TIntermNode *root) +{ + TVersionGLSL versionGLSL(getShaderType(), getPragma()); + root->traverse(&versionGLSL); + int version = versionGLSL.getVersion(); + // We need to write version directive only if it is greater than 110. + // If there is no version directive in the shader, 110 is implied. + if (version > 110) + { + TInfoSinkBase& sink = getInfoSink().obj; + sink << "#version " << version << "\n"; + } +} + void TranslatorGLSL::writeExtensionBehavior() { TInfoSinkBase& sink = getInfoSink().obj; const TExtensionBehavior& extensionBehavior = getExtensionBehavior(); diff --git a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h index 3c6c2e426a..766d8d910e 100644 --- a/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/TranslatorGLSL.h @@ -9,14 +9,16 @@ #include "compiler/translator/Compiler.h" -class TranslatorGLSL : public TCompiler { -public: +class TranslatorGLSL : public TCompiler +{ + public: TranslatorGLSL(sh::GLenum type, ShShaderSpec spec); -protected: - virtual void translate(TIntermNode* root); + protected: + virtual void translate(TIntermNode *root); -private: + private: + void writeVersion(TIntermNode *root); void writeExtensionBehavior(); }; diff --git a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp index c1a7b7524f..896e1cd7a0 100644 --- a/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp +++ b/src/3rdparty/angle/src/compiler/translator/ValidateLimitations.cpp @@ -94,6 +94,7 @@ const char *GetOperatorString(TOperator op) case EOpLogicalXor: return "^^"; case EOpLogicalAnd: return "&&"; case EOpNegative: return "-"; + case EOpPositive: return "+"; case EOpVectorLogicalNot: return "not"; case EOpLogicalNot: return "!"; case EOpPostIncrement: return "++"; diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp index f26c1566ac..d8e13788b7 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.cpp @@ -5,6 +5,7 @@ // #include "angle_gl.h" +#include "compiler/translator/SymbolTable.h" #include "compiler/translator/VariableInfo.h" #include "compiler/translator/util.h" #include "common/utilities.h" @@ -131,7 +132,8 @@ CollectVariables::CollectVariables(std::vector *attribs, std::vector *uniforms, std::vector *varyings, std::vector *interfaceBlocks, - ShHashFunction64 hashFunction) + ShHashFunction64 hashFunction, + const TSymbolTable &symbolTable) : mAttribs(attribs), mOutputVariables(outputVariables), mUniforms(uniforms), @@ -140,7 +142,10 @@ CollectVariables::CollectVariables(std::vector *attribs, mPointCoordAdded(false), mFrontFacingAdded(false), mFragCoordAdded(false), - mHashFunction(hashFunction) + mPositionAdded(false), + mPointSizeAdded(false), + mHashFunction(hashFunction), + mSymbolTable(symbolTable) { } @@ -200,12 +205,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) if (!mFragCoordAdded) { Varying info; - info.name = "gl_FragCoord"; - info.mappedName = "gl_FragCoord"; + const char kName[] = "gl_FragCoord"; + info.name = kName; + info.mappedName = kName; info.type = GL_FLOAT_VEC4; info.arraySize = 0; - info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. + info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mFragCoordAdded = true; } @@ -214,12 +221,14 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) if (!mFrontFacingAdded) { Varying info; - info.name = "gl_FrontFacing"; - info.mappedName = "gl_FrontFacing"; + const char kName[] = "gl_FrontFacing"; + info.name = kName; + info.mappedName = kName; info.type = GL_BOOL; info.arraySize = 0; info.precision = GL_NONE; info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mFrontFacingAdded = true; } @@ -228,16 +237,50 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) if (!mPointCoordAdded) { Varying info; - info.name = "gl_PointCoord"; - info.mappedName = "gl_PointCoord"; + const char kName[] = "gl_PointCoord"; + info.name = kName; + info.mappedName = kName; info.type = GL_FLOAT_VEC2; info.arraySize = 0; - info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter. + info.precision = GL_MEDIUM_FLOAT; // Defined by spec. info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); mVaryings->push_back(info); mPointCoordAdded = true; } return; + case EvqPosition: + if (!mPositionAdded) + { + Varying info; + const char kName[] = "gl_Position"; + info.name = kName; + info.mappedName = kName; + info.type = GL_FLOAT_VEC4; + info.arraySize = 0; + info.precision = GL_HIGH_FLOAT; // Defined by spec. + info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); + mVaryings->push_back(info); + mPositionAdded = true; + } + return; + case EvqPointSize: + if (!mPointSizeAdded) + { + Varying info; + const char kName[] = "gl_PointSize"; + info.name = kName; + info.mappedName = kName; + info.type = GL_FLOAT; + info.arraySize = 0; + info.precision = GL_MEDIUM_FLOAT; // Defined by spec. + info.staticUse = true; + info.isInvariant = mSymbolTable.isVaryingInvariant(kName); + mVaryings->push_back(info); + mPointSizeAdded = true; + } + return; default: break; } @@ -251,8 +294,10 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) class NameHashingTraverser : public GetVariableTraverser { public: - NameHashingTraverser(ShHashFunction64 hashFunction) - : mHashFunction(hashFunction) + NameHashingTraverser(ShHashFunction64 hashFunction, + const TSymbolTable &symbolTable) + : GetVariableTraverser(symbolTable), + mHashFunction(hashFunction) {} private: @@ -312,7 +357,7 @@ void CollectVariables::visitVariable(const TIntermSymbol *variable, const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field); const TType &fieldType = *field.type(); - GetVariableTraverser traverser; + GetVariableTraverser traverser(mSymbolTable); traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields); interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor); @@ -325,7 +370,7 @@ template void CollectVariables::visitVariable(const TIntermSymbol *variable, std::vector *infoList) const { - NameHashingTraverser traverser(mHashFunction); + NameHashingTraverser traverser(mHashFunction, mSymbolTable); traverser.traverse(variable->getType(), variable->getSymbol(), infoList); } @@ -421,9 +466,8 @@ bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode) return true; } -template -void ExpandVariables(const std::vector &compact, - std::vector *expanded) +void ExpandUniforms(const std::vector &compact, + std::vector *expanded) { for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++) { @@ -432,7 +476,4 @@ void ExpandVariables(const std::vector &compact, } } -template void ExpandVariables(const std::vector &, std::vector *); -template void ExpandVariables(const std::vector &, std::vector *); - } diff --git a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h index 5ac4c46baa..92d376d879 100644 --- a/src/3rdparty/angle/src/compiler/translator/VariableInfo.h +++ b/src/3rdparty/angle/src/compiler/translator/VariableInfo.h @@ -11,6 +11,8 @@ #include "compiler/translator/IntermNode.h" +class TSymbolTable; + namespace sh { @@ -23,7 +25,8 @@ class CollectVariables : public TIntermTraverser std::vector *uniforms, std::vector *varyings, std::vector *interfaceBlocks, - ShHashFunction64 hashFunction); + ShHashFunction64 hashFunction, + const TSymbolTable &symbolTable); virtual void visitSymbol(TIntermSymbol *symbol); virtual bool visitAggregate(Visit, TIntermAggregate *node); @@ -48,13 +51,17 @@ class CollectVariables : public TIntermTraverser bool mFrontFacingAdded; bool mFragCoordAdded; + bool mPositionAdded; + bool mPointSizeAdded; + ShHashFunction64 mHashFunction; + + const TSymbolTable &mSymbolTable; }; -// Expand struct variables to flattened lists of split variables -template -void ExpandVariables(const std::vector &compact, - std::vector *expanded); +// Expand struct uniforms to flattened lists of split variables +void ExpandUniforms(const std::vector &compact, + std::vector *expanded); } diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp index 8edbd009b0..05b111a7a7 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.cpp @@ -26,18 +26,12 @@ static const int GLSL_VERSION_120 = 120; // GLSL 1.2 relaxed the restriction on arrays, section 5.8: "Variables that // are built-in types, entire structures or arrays... are all l-values." // -// TODO(alokp): The following two cases of invariant decalaration get lost -// during parsing - they do not get carried over to the intermediate tree. -// Handle these cases: -// 1. When a pragma is used to force all output variables to be invariant: -// - #pragma STDGL invariant(all) -// 2. When a previously decalared or built-in variable is marked invariant: -// - invariant gl_Position; -// - varying vec3 color; invariant color; -// -TVersionGLSL::TVersionGLSL(sh::GLenum type) - : mVersion(GLSL_VERSION_110) +TVersionGLSL::TVersionGLSL(sh::GLenum type, const TPragma &pragma) { + if (pragma.stdgl.invariantAll) + mVersion = GLSL_VERSION_120; + else + mVersion = GLSL_VERSION_110; } void TVersionGLSL::visitSymbol(TIntermSymbol *node) diff --git a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h index 30f5a138a0..72368e39d6 100644 --- a/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h +++ b/src/3rdparty/angle/src/compiler/translator/VersionGLSL.h @@ -9,6 +9,8 @@ #include "compiler/translator/IntermNode.h" +#include "compiler/translator/Pragma.h" + // Traverses the intermediate tree to return the minimum GLSL version // required to legally access all built-in features used in the shader. // GLSL 1.1 which is mandated by OpenGL 2.0 provides: @@ -27,7 +29,7 @@ class TVersionGLSL : public TIntermTraverser { public: - TVersionGLSL(sh::GLenum type); + TVersionGLSL(sh::GLenum type, const TPragma &pragma); // Returns 120 if the following is used the shader: // - "invariant", diff --git a/src/3rdparty/angle/src/compiler/translator/glslang.y b/src/3rdparty/angle/src/compiler/translator/glslang.y index 5c945ad5ad..e271de978c 100644 --- a/src/3rdparty/angle/src/compiler/translator/glslang.y +++ b/src/3rdparty/angle/src/compiler/translator/glslang.y @@ -354,6 +354,15 @@ function_call // Treat it like a built-in unary operator. // $$ = context->intermediate.addUnaryMath(op, $1.intermNode, @1); + const TType& returnType = fnCandidate->getReturnType(); + if (returnType.getBasicType() == EbtBool) { + // Bool types should not have precision, so we'll override any precision + // that might have been set by addUnaryMath. + $$->setType(returnType); + } else { + // addUnaryMath has set the precision of the node based on the operand. + $$->setTypePreservePrecision(returnType); + } if ($$ == 0) { std::stringstream extraInfoStream; extraInfoStream << "built in unary operator function. Type: " << static_cast($1.intermNode)->getCompleteString(); @@ -362,20 +371,29 @@ function_call YYERROR; } } else { - $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1); + TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, op, @1); + aggregate->setType(fnCandidate->getReturnType()); + aggregate->setPrecisionFromChildren(); + $$ = aggregate; } } else { // This is a real function call - $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1); - $$->setType(fnCandidate->getReturnType()); + TIntermAggregate *aggregate = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, @1); + aggregate->setType(fnCandidate->getReturnType()); // this is how we know whether the given function is a builtIn function or a user defined function // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also // if builtIn == true, it's definitely a builtIn function with EOpNull if (!builtIn) - $$->getAsAggregate()->setUserDefined(); - $$->getAsAggregate()->setName(fnCandidate->getMangledName()); + aggregate->setUserDefined(); + aggregate->setName(fnCandidate->getMangledName()); + + // This needs to happen after the name is set + if (builtIn) + aggregate->setBuiltInFunctionPrecision(); + + $$ = aggregate; TQualifier qual; for (size_t i = 0; i < fnCandidate->getParamCount(); ++i) { @@ -388,7 +406,6 @@ function_call } } } - $$->setType(fnCandidate->getReturnType()); } else { // error message was put out by PaFindFunction() // Put on a dummy node for error recovery @@ -500,6 +517,7 @@ unary_expression const char* errorOp = ""; switch($1.op) { case EOpNegative: errorOp = "-"; break; + case EOpPositive: errorOp = "+"; break; case EOpLogicalNot: errorOp = "!"; break; default: break; } @@ -514,7 +532,7 @@ unary_expression // Grammar Note: No traditional style type casts. unary_operator - : PLUS { $$.op = EOpNull; } + : PLUS { $$.op = EOpPositive; } | DASH { $$.op = EOpNegative; } | BANG { $$.op = EOpLogicalNot; } ; @@ -762,7 +780,7 @@ declaration TIntermAggregate *prototype = new TIntermAggregate; prototype->setType(function.getReturnType()); - prototype->setName(function.getName()); + prototype->setName(function.getMangledName()); for (size_t i = 0; i < function.getParamCount(); i++) { diff --git a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp index 56340c6f9e..00780f0454 100644 --- a/src/3rdparty/angle/src/compiler/translator/intermOut.cpp +++ b/src/3rdparty/angle/src/compiler/translator/intermOut.cpp @@ -62,7 +62,9 @@ TString TType::getCompleteString() const TStringStream stream; if (qualifier != EvqTemporary && qualifier != EvqGlobal) - stream << getQualifierString() << " " << getPrecisionString() << " "; + stream << getQualifierString() << " "; + if (precision != EbpUndefined) + stream << getPrecisionString() << " "; if (array) stream << "array[" << getArraySize() << "] of "; if (isMatrix()) @@ -221,6 +223,7 @@ bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node) switch (node->getOp()) { case EOpNegative: out << "Negate value"; break; + case EOpPositive: out << "Positive sign"; break; case EOpVectorLogicalNot: case EOpLogicalNot: out << "Negate conditional"; break; @@ -292,6 +295,7 @@ bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node) case EOpFunction: out << "Function Definition: " << node->getName(); break; case EOpFunctionCall: out << "Function Call: " << node->getName(); break; case EOpParameters: out << "Function Parameters: "; break; + case EOpPrototype: out << "Function Prototype: " << node->getName(); break; case EOpConstructFloat: out << "Construct float"; break; case EOpConstructVec2: out << "Construct vec2"; break; diff --git a/src/3rdparty/angle/src/compiler/translator/util.cpp b/src/3rdparty/angle/src/compiler/translator/util.cpp index f74c7d1173..8cc06a658a 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.cpp +++ b/src/3rdparty/angle/src/compiler/translator/util.cpp @@ -9,6 +9,7 @@ #include #include "compiler/preprocessor/numeric_lex.h" +#include "compiler/translator/SymbolTable.h" #include "common/utilities.h" bool atof_clamp(const char *str, float *value) @@ -281,8 +282,47 @@ InterpolationType GetInterpolationType(TQualifier qualifier) } } +GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable) + : mSymbolTable(symbolTable) +{ +} + +template void GetVariableTraverser::setTypeSpecificInfo( + const TType &type, const TString& name, InterfaceBlockField *variable); +template void GetVariableTraverser::setTypeSpecificInfo( + const TType &type, const TString& name, ShaderVariable *variable); +template void GetVariableTraverser::setTypeSpecificInfo( + const TType &type, const TString& name, Uniform *variable); + +template<> +void GetVariableTraverser::setTypeSpecificInfo( + const TType &type, const TString& name, Varying *variable) +{ + ASSERT(variable); + switch (type.getQualifier()) + { + case EvqInvariantVaryingIn: + case EvqInvariantVaryingOut: + variable->isInvariant = true; + break; + case EvqVaryingIn: + case EvqVaryingOut: + if (mSymbolTable.isVaryingInvariant(name)) + { + variable->isInvariant = true; + } + break; + default: + break; + } + + variable->interpolation = GetInterpolationType(type.getQualifier()); +} + template -void GetVariableTraverser::traverse(const TType &type, const TString &name, std::vector *output) +void GetVariableTraverser::traverse(const TType &type, + const TString &name, + std::vector *output) { const TStructure *structure = type.getStruct(); @@ -309,15 +349,16 @@ void GetVariableTraverser::traverse(const TType &type, const TString &name, std: traverse(*field->type(), field->name(), &variable.fields); } } - + setTypeSpecificInfo(type, name, &variable); visitVariable(&variable); ASSERT(output); output->push_back(variable); } +template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); +template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); -template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector *); } diff --git a/src/3rdparty/angle/src/compiler/translator/util.h b/src/3rdparty/angle/src/compiler/translator/util.h index 241e2cc1c2..fb5308759e 100644 --- a/src/3rdparty/angle/src/compiler/translator/util.h +++ b/src/3rdparty/angle/src/compiler/translator/util.h @@ -24,6 +24,8 @@ extern bool atof_clamp(const char *str, float *value); // Return false if overflow happens. extern bool atoi_clamp(const char *str, int *value); +class TSymbolTable; + namespace sh { @@ -38,7 +40,7 @@ TString ArrayString(const TType &type); class GetVariableTraverser { public: - GetVariableTraverser() {} + GetVariableTraverser(const TSymbolTable &symbolTable); template void traverse(const TType &type, const TString &name, std::vector *output); @@ -48,6 +50,14 @@ class GetVariableTraverser virtual void visitVariable(ShaderVariable *newVar) {} private: + // Helper function called by traverse() to fill specific fields + // for attributes/varyings/uniforms. + template + void setTypeSpecificInfo( + const TType &type, const TString &name, VarT *variable) {} + + const TSymbolTable &mSymbolTable; + DISALLOW_COPY_AND_ASSIGN(GetVariableTraverser); }; diff --git a/src/3rdparty/angle/src/libEGL/AttributeMap.cpp b/src/3rdparty/angle/src/libEGL/AttributeMap.cpp new file mode 100644 index 0000000000..28dd3d842e --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/AttributeMap.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#include "libEGL/AttributeMap.h" + +namespace egl +{ + +AttributeMap::AttributeMap() +{ +} + +AttributeMap::AttributeMap(const EGLint *attributes) +{ + for (const EGLint *curAttrib = attributes; curAttrib[0] != EGL_NONE; curAttrib += 2) + { + insert(curAttrib[0], curAttrib[1]); + } +} + +void AttributeMap::insert(EGLint key, EGLint value) +{ + mAttributes[key] = value; +} + +bool AttributeMap::contains(EGLint key) const +{ + return (mAttributes.find(key) != mAttributes.end()); +} + +EGLint AttributeMap::get(EGLint key, EGLint defaultValue) const +{ + std::map::const_iterator iter = mAttributes.find(key); + return (mAttributes.find(key) != mAttributes.end()) ? iter->second : defaultValue; +} + +} diff --git a/src/3rdparty/angle/src/libEGL/AttributeMap.h b/src/3rdparty/angle/src/libEGL/AttributeMap.h new file mode 100644 index 0000000000..f2f082fe21 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/AttributeMap.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +#ifndef LIBEGL_ATTRIBUTEMAP_H_ +#define LIBEGL_ATTRIBUTEMAP_H_ + +#include + +#include + +namespace egl +{ + +class AttributeMap +{ + public: + AttributeMap(); + explicit AttributeMap(const EGLint *attributes); + + virtual void insert(EGLint key, EGLint value); + virtual bool contains(EGLint key) const; + virtual EGLint get(EGLint key, EGLint defaultValue) const; + + private: + std::map mAttributes; +}; + +} + +#endif // LIBEGL_ATTRIBUTEMAP_H_ diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp index 5a50e4baf5..eea93b1d87 100644 --- a/src/3rdparty/angle/src/libEGL/Display.cpp +++ b/src/3rdparty/angle/src/libEGL/Display.cpp @@ -35,32 +35,36 @@ static DisplayMap *GetDisplayMap() return &displays; } -egl::Display *Display::getDisplay(EGLNativeDisplayType displayId, EGLint displayType) +egl::Display *Display::getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap) { + Display *display = NULL; + DisplayMap *displays = GetDisplayMap(); DisplayMap::const_iterator iter = displays->find(displayId); if (iter != displays->end()) { - return iter->second; + display = iter->second; + } + else + { + display = new egl::Display(displayId); + displays->insert(std::make_pair(displayId, display)); } - - // FIXME: Check if displayId is a valid display device context - egl::Display *display = new egl::Display(displayId, displayType); - displays->insert(std::make_pair(displayId, display)); + // Apply new attributes if the display is not initialized yet. + if (!display->isInitialized()) + { + display->setAttributes(attribMap); + } return display; } -Display::Display(EGLNativeDisplayType displayId, EGLint displayType) +Display::Display(EGLNativeDisplayType displayId) : mDisplayId(displayId), - mRequestedDisplayType(displayType), + mAttributeMap(), mRenderer(NULL) { -#if defined(ANGLE_PLATFORM_WINRT) - if (mDisplayId) - mDisplayId->AddRef(); -#endif } Display::~Display() @@ -73,28 +77,29 @@ Display::~Display() { displays->erase(iter); } - -#if defined(ANGLE_PLATFORM_WINRT) - if (mDisplayId) - mDisplayId->Release(); -#endif } -bool Display::initialize() +void Display::setAttributes(const AttributeMap &attribMap) +{ + mAttributeMap = attribMap; +} + +Error Display::initialize() { if (isInitialized()) { - return true; + return Error(EGL_SUCCESS); } - mRenderer = glCreateRenderer(this, mDisplayId, mRequestedDisplayType); + mRenderer = glCreateRenderer(this, mDisplayId, mAttributeMap); if (!mRenderer) { terminate(); - return error(EGL_NOT_INITIALIZED, false); + return Error(EGL_NOT_INITIALIZED); } + //TODO(jmadill): should be part of caps? EGLint minSwapInterval = mRenderer->getMinSwapInterval(); EGLint maxSwapInterval = mRenderer->getMaxSwapInterval(); EGLint maxTextureSize = mRenderer->getRendererCaps().max2DTextureSize; @@ -125,13 +130,13 @@ bool Display::initialize() if (!isInitialized()) { terminate(); - return false; + return Error(EGL_NOT_INITIALIZED); } initDisplayExtensionString(); initVendorString(); - return true; + return Error(EGL_SUCCESS); } void Display::terminate() @@ -148,6 +153,8 @@ void Display::terminate() glDestroyRenderer(mRenderer); mRenderer = NULL; + + mConfigSet.mSet.clear(); } bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) @@ -202,7 +209,7 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) -EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList) +Error Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList, EGLSurface *outSurface) { const Config *configuration = mConfigSet.get(config); EGLint postSubBufferSupported = EGL_FALSE; @@ -223,9 +230,9 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co case EGL_BACK_BUFFER: break; case EGL_SINGLE_BUFFER: - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported + return Error(EGL_BAD_MATCH); // Rendering directly to front buffer not supported default: - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_POST_SUB_BUFFER_SUPPORTED_NV: @@ -241,11 +248,11 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co fixedSize = attribList[1]; break; case EGL_VG_COLORSPACE: - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); case EGL_VG_ALPHA_FORMAT: - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); default: - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } attribList += 2; @@ -254,7 +261,7 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co if (width < 0 || height < 0) { - return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + return Error(EGL_BAD_PARAMETER); } if (!fixedSize) @@ -265,29 +272,33 @@ EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig co if (hasExistingWindowSurface(window)) { - return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + return Error(EGL_BAD_ALLOC); } if (mRenderer->testDeviceLost(false)) { - if (!restoreLostDevice()) - return EGL_NO_SURFACE; + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } } Surface *surface = new Surface(this, configuration, window, fixedSize, width, height, postSubBufferSupported); - - if (!surface->initialize()) + Error error = surface->initialize(); + if (error.isError()) { - delete surface; - return EGL_NO_SURFACE; + SafeDelete(surface); + return error; } mSurfaceSet.insert(surface); - return success(surface); + *outSurface = surface; + return Error(EGL_SUCCESS); } -EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList) +Error Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList, EGLSurface *outSurface) { EGLint width = 0, height = 0; EGLenum textureFormat = EGL_NO_TEXTURE; @@ -319,7 +330,7 @@ EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, textureFormat = attribList[1]; break; default: - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_TEXTURE_TARGET: @@ -330,19 +341,19 @@ EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, textureTarget = attribList[1]; break; default: - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } break; case EGL_MIPMAP_TEXTURE: if (attribList[1] != EGL_FALSE) - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); break; case EGL_VG_COLORSPACE: - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); case EGL_VG_ALPHA_FORMAT: - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); default: - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } attribList += 2; @@ -351,88 +362,100 @@ EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, if (width < 0 || height < 0) { - return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + return Error(EGL_BAD_PARAMETER); } if (width == 0 || height == 0) { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } if (textureFormat != EGL_NO_TEXTURE && !mRenderer->getRendererExtensions().textureNPOT && (!gl::isPow2(width) || !gl::isPow2(height))) { - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); } if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) || (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE)) { - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); } if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT)) { - return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + return Error(EGL_BAD_MATCH); } if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) || (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE)) { - return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return Error(EGL_BAD_ATTRIBUTE); } if (mRenderer->testDeviceLost(false)) { - if (!restoreLostDevice()) - return EGL_NO_SURFACE; + Error error = restoreLostDevice(); + if (error.isError()) + { + return error; + } } Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget); - - if (!surface->initialize()) + Error error = surface->initialize(); + if (error.isError()) { - delete surface; - return EGL_NO_SURFACE; + SafeDelete(surface); + return error; } mSurfaceSet.insert(surface); - return success(surface); + *outSurface = surface; + return Error(EGL_SUCCESS); } -EGLContext Display::createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, bool robustAccess) +Error Display::createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, + bool robustAccess, EGLContext *outContext) { if (!mRenderer) { - return EGL_NO_CONTEXT; + *outContext = EGL_NO_CONTEXT; + return Error(EGL_SUCCESS); } else if (mRenderer->testDeviceLost(false)) // Lost device { - if (!restoreLostDevice()) + Error error = restoreLostDevice(); + if (error.isError()) { - return error(EGL_CONTEXT_LOST, EGL_NO_CONTEXT); + return error; } } + //TODO(jmadill): shader model is not cross-platform if (clientVersion > 2 && mRenderer->getMajorShaderModel() < 4) { - return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); + return Error(EGL_BAD_CONFIG); } gl::Context *context = glCreateContext(clientVersion, shareContext, mRenderer, notifyResets, robustAccess); mContextSet.insert(context); - return success(context); + *outContext = context; + return Error(EGL_SUCCESS); } -bool Display::restoreLostDevice() +Error Display::restoreLostDevice() { for (ContextSet::iterator ctx = mContextSet.begin(); ctx != mContextSet.end(); ctx++) { if ((*ctx)->isResetNotificationEnabled()) - return false; // If reset notifications have been requested, application must delete all contexts first + { + // If reset notifications have been requested, application must delete all contexts first + return Error(EGL_CONTEXT_LOST); + } } - + // Release surface resources to make the Reset() succeed for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) { @@ -441,16 +464,20 @@ bool Display::restoreLostDevice() if (!mRenderer->resetDevice()) { - return error(EGL_BAD_ALLOC, false); + return Error(EGL_BAD_ALLOC); } // Restore any surfaces that may have been lost for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) { - (*surface)->resetSwapChain(); + Error error = (*surface)->resetSwapChain(); + if (error.isError()) + { + return error; + } } - return true; + return Error(EGL_SUCCESS); } @@ -472,7 +499,6 @@ void Display::notifyDeviceLost() { (*context)->markContextLost(); } - egl::error(EGL_CONTEXT_LOST); } void Display::recreateSwapChains() @@ -604,10 +630,11 @@ void Display::initVendorString() LUID adapterLuid = {0}; + //TODO(jmadill): LUID is not cross-platform if (mRenderer && mRenderer->getLUID(&adapterLuid)) { char adapterLuidString[64]; - snprintf(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); + sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); mVendorString += adapterLuidString; } diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h index 73ba7673ff..b3ffcc84c5 100644 --- a/src/3rdparty/angle/src/libEGL/Display.h +++ b/src/3rdparty/angle/src/libEGL/Display.h @@ -14,7 +14,9 @@ #include #include +#include "libEGL/Error.h" #include "libEGL/Config.h" +#include "libEGL/AttributeMap.h" namespace gl { @@ -30,10 +32,10 @@ class Display public: ~Display(); - bool initialize(); + Error initialize(); void terminate(); - static egl::Display *getDisplay(EGLNativeDisplayType displayId, EGLint displayType); + static egl::Display *getDisplay(EGLNativeDisplayType displayId, const AttributeMap &attribMap); static const char *getExtensionString(egl::Display *display); @@ -43,9 +45,10 @@ class Display bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); - EGLSurface createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList); - EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); - EGLContext createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, bool robustAccess); + Error createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList, EGLSurface *outSurface); + Error createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList, EGLSurface *outSurface); + Error createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, + bool robustAccess, EGLContext *outContext); void destroySurface(egl::Surface *surface); void destroyContext(gl::Context *context); @@ -64,18 +67,19 @@ class Display const char *getExtensionString() const; const char *getVendorString() const; - EGLNativeDisplayType getDisplayId() const { return mDisplayId; } private: DISALLOW_COPY_AND_ASSIGN(Display); - Display(EGLNativeDisplayType displayId, EGLint displayType); + Display(EGLNativeDisplayType displayId); - bool restoreLostDevice(); + void setAttributes(const AttributeMap &attribMap); + + Error restoreLostDevice(); EGLNativeDisplayType mDisplayId; - EGLint mRequestedDisplayType; + AttributeMap mAttributeMap; typedef std::set SurfaceSet; SurfaceSet mSurfaceSet; diff --git a/src/3rdparty/angle/src/libEGL/Error.cpp b/src/3rdparty/angle/src/libEGL/Error.cpp new file mode 100644 index 0000000000..df5f163d32 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Error.cpp @@ -0,0 +1,48 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Error.cpp: Implements the egl::Error class which encapsulates an EGL error +// and optional error message. + +#include "libEGL/Error.h" + +#include "common/angleutils.h" + +#include + +namespace egl +{ + +Error::Error(EGLint errorCode) + : mCode(errorCode), + mMessage() +{ +} + +Error::Error(EGLint errorCode, const char *msg, ...) + : mCode(errorCode), + mMessage() +{ + va_list vararg; + va_start(vararg, msg); + mMessage = FormatString(msg, vararg); + va_end(vararg); +} + +Error::Error(const Error &other) + : mCode(other.mCode), + mMessage(other.mMessage) +{ +} + +Error &Error::operator=(const Error &other) +{ + mCode = other.mCode; + mMessage = other.mMessage; + return *this; +} + +} diff --git a/src/3rdparty/angle/src/libEGL/Error.h b/src/3rdparty/angle/src/libEGL/Error.h new file mode 100644 index 0000000000..71805d2fb7 --- /dev/null +++ b/src/3rdparty/angle/src/libEGL/Error.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Error.h: Defines the egl::Error class which encapsulates an EGL error +// and optional error message. + +#ifndef LIBEGL_ERROR_H_ +#define LIBEGL_ERROR_H_ + +#include + +#include + +namespace egl +{ + +class Error +{ + public: + explicit Error(EGLint errorCode); + Error(EGLint errorCode, const char *msg, ...); + Error(const Error &other); + Error &operator=(const Error &other); + + EGLint getCode() const { return mCode; } + bool isError() const { return (mCode != EGL_SUCCESS); } + + const std::string &getMessage() const { return mMessage; } + + private: + EGLint mCode; + std::string mMessage; +}; + +} + +#endif // LIBEGL_ERROR_H_ diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp index fa7996152a..b664a8530e 100644 --- a/src/3rdparty/angle/src/libEGL/Surface.cpp +++ b/src/3rdparty/angle/src/libEGL/Surface.cpp @@ -22,23 +22,19 @@ #include "libEGL/main.h" #include "libEGL/Display.h" -#if defined(ANGLE_PLATFORM_WINRT) -# include "wrl.h" -# include "windows.graphics.display.h" -# include "windows.ui.core.h" -using namespace ABI::Windows::Graphics::Display; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::UI::Core; -using namespace Microsoft::WRL; -#endif +#include "common/NativeWindow.h" + +//TODO(jmadill): phase this out +#include "libGLESv2/renderer/d3d/RendererD3D.h" namespace egl { -Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) - : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported) +Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) + : mDisplay(display), mConfig(config), mNativeWindow(window, display->getDisplayId()), mPostSubBufferSupported(postSubBufferSupported) { - mRenderer = mDisplay->getRenderer(); + //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) + mRenderer = static_cast(mDisplay->getRenderer()); mSwapChain = NULL; mShareHandle = NULL; mTexture = NULL; @@ -51,27 +47,19 @@ Surface::Surface(Display *display, const Config *config, EGLNativeWindowType win mSwapInterval = -1; mWidth = width; mHeight = height; + mFixedWidth = mWidth; + mFixedHeight = mHeight; setSwapInterval(1); mFixedSize = fixedSize; - mSwapFlags = rx::SWAP_NORMAL; -#if defined(ANGLE_PLATFORM_WINRT) - if (mWindow) - mWindow->AddRef(); - mScaleFactor = 1.0; - mSizeToken.value = 0; - mDpiToken.value = 0; -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - mOrientationToken.value = 0; -# endif -#endif subclassWindow(); } Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) - : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) + : mDisplay(display), mNativeWindow(NULL, NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) { - mRenderer = mDisplay->getRenderer(); + //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) + mRenderer = static_cast(mDisplay->getRenderer()); mSwapChain = NULL; mWindowSubclassed = false; mTexture = NULL; @@ -85,90 +73,33 @@ Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGL setSwapInterval(1); // This constructor is for offscreen surfaces, which are always fixed-size. mFixedSize = EGL_TRUE; - mSwapFlags = rx::SWAP_NORMAL; -#if defined(ANGLE_PLATFORM_WINRT) - mScaleFactor = 1.0; - mSizeToken.value = 0; - mDpiToken.value = 0; -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - mOrientationToken.value = 0; -# endif -#endif + mFixedWidth = mWidth; + mFixedHeight = mHeight; } Surface::~Surface() { -#if defined(ANGLE_PLATFORM_WINRT) - if (mSizeToken.value) { - ComPtr coreWindow; - HRESULT hr = mWindow->QueryInterface(coreWindow.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - - hr = coreWindow->remove_SizeChanged(mSizeToken); - ASSERT(SUCCEEDED(hr)); - } - if (mDpiToken.value) { - ComPtr displayInformation; - HRESULT hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - - hr = displayInformation->remove_DpiChanged(mDpiToken); - ASSERT(SUCCEEDED(hr)); - } -# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - if (mOrientationToken.value) { - ComPtr displayInformation; - HRESULT hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - - hr = displayInformation->remove_OrientationChanged(mOrientationToken); - ASSERT(SUCCEEDED(hr)); - } -# endif -#endif unsubclassWindow(); release(); } -bool Surface::initialize() +Error Surface::initialize() { -#if defined(ANGLE_PLATFORM_WINRT) - if (!mFixedSize) { - HRESULT hr; - ComPtr displayInformation; - hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - onDpiChanged(displayInformation.Get(), 0); - hr = displayInformation->add_DpiChanged(Callback>(this, &Surface::onDpiChanged).Get(), - &mDpiToken); - ASSERT(SUCCEEDED(hr)); - -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - onOrientationChanged(displayInformation.Get(), 0); - hr = displayInformation->add_OrientationChanged(Callback>(this, &Surface::onOrientationChanged).Get(), - &mOrientationToken); - ASSERT(SUCCEEDED(hr)); -# endif - - ComPtr coreWindow; - hr = mWindow->QueryInterface(coreWindow.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - - Rect rect; - hr = coreWindow->get_Bounds(&rect); - ASSERT(SUCCEEDED(hr)); - mWidth = rect.Width * mScaleFactor; - mHeight = rect.Height * mScaleFactor; - hr = coreWindow->add_SizeChanged(Callback>(this, &Surface::onSizeChanged).Get(), - &mSizeToken); - ASSERT(SUCCEEDED(hr)); + if (mNativeWindow.getNativeWindow()) + { + if (!mNativeWindow.initialize()) + { + return Error(EGL_BAD_SURFACE); + } } -#endif - if (!resetSwapChain()) - return false; + Error error = resetSwapChain(); + if (error.isError()) + { + return error; + } - return true; + return Error(EGL_SUCCESS); } void Surface::release() @@ -181,85 +112,80 @@ void Surface::release() mTexture->releaseTexImage(); mTexture = NULL; } - -#if defined(ANGLE_PLATFORM_WINRT) - if (mWindow) - mWindow->Release(); -#endif } -bool Surface::resetSwapChain() +Error Surface::resetSwapChain() { ASSERT(!mSwapChain); int width; int height; -#if !defined(ANGLE_PLATFORM_WINRT) if (!mFixedSize) { RECT windowRect; - if (!GetClientRect(getWindowHandle(), &windowRect)) + if (!mNativeWindow.getClientRect(&windowRect)) { ASSERT(false); - ERR("Could not retrieve the window dimensions"); - return error(EGL_BAD_SURFACE, false); + return Error(EGL_BAD_SURFACE, "Could not retrieve the window dimensions"); } width = windowRect.right - windowRect.left; height = windowRect.bottom - windowRect.top; } else -#endif { // non-window surface - size is determined at creation width = mWidth; height = mHeight; } - mSwapChain = mRenderer->createSwapChain(mWindow, mShareHandle, + mSwapChain = mRenderer->createSwapChain(mNativeWindow, mShareHandle, mConfig->mRenderTargetFormat, mConfig->mDepthStencilFormat); if (!mSwapChain) { - return error(EGL_BAD_ALLOC, false); + return Error(EGL_BAD_ALLOC); } - if (!resetSwapChain(width, height)) + Error error = resetSwapChain(width, height); + if (error.isError()) { - delete mSwapChain; - mSwapChain = NULL; - return false; + SafeDelete(mSwapChain); + return error; } - return true; + return Error(EGL_SUCCESS); } -bool Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) +Error Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) { - ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); - EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + backbufferWidth = std::max(1, backbufferWidth); + backbufferHeight = std::max(1, backbufferHeight); +#endif + EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight); if (status == EGL_CONTEXT_LOST) { mDisplay->notifyDeviceLost(); - return false; + return Error(status); } else if (status != EGL_SUCCESS) { - return error(status, false); + return Error(status); } mWidth = backbufferWidth; mHeight = backbufferHeight; - return true; + return Error(EGL_SUCCESS); } -bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) +Error Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) { ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); ASSERT(mSwapChain); @@ -269,69 +195,71 @@ bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight) if (status == EGL_CONTEXT_LOST) { mRenderer->notifyDeviceLost(); - return false; + return Error(status); } else if (status != EGL_SUCCESS) { - return error(status, false); + return Error(status); } mWidth = backbufferWidth; mHeight = backbufferHeight; mSwapIntervalDirty = false; - return true; + return Error(EGL_SUCCESS); } -bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { if (!mSwapChain) { - return true; + return Error(EGL_SUCCESS); } - if (x + width > mWidth) + if (x + width > abs(mWidth)) { - width = mWidth - x; + width = abs(mWidth) - x; } - if (y + height > mHeight) + if (y + height > abs(mHeight)) { - height = mHeight - y; + height = abs(mHeight) - y; } if (width == 0 || height == 0) { - return true; + return Error(EGL_SUCCESS); } - EGLint status = mSwapChain->swapRect(x, y, width, height, mSwapFlags); + ASSERT(width > 0); + ASSERT(height > 0); + + EGLint status = mSwapChain->swapRect(x, y, width, height); if (status == EGL_CONTEXT_LOST) { mRenderer->notifyDeviceLost(); - return false; + return Error(status); } else if (status != EGL_SUCCESS) { - return error(status, false); + return Error(status); } checkForOutOfDateSwapChain(); - return true; + return Error(EGL_SUCCESS); } EGLNativeWindowType Surface::getWindowHandle() { - return mWindow; + return mNativeWindow.getNativeWindow(); } - +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) #define kSurfaceProperty _TEXT("Egl::SurfaceOwner") #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") -#if !defined(ANGLE_PLATFORM_WINRT) static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { if (message == WM_SIZE) @@ -349,45 +277,50 @@ static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam void Surface::subclassWindow() { -#if !defined(ANGLE_PLATFORM_WINRT) - if (!mWindow) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) { return; } DWORD processId; - DWORD threadId = GetWindowThreadProcessId(mWindow, &processId); + DWORD threadId = GetWindowThreadProcessId(window, &processId); if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId()) { return; } SetLastError(0); - LONG_PTR oldWndProc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); + LONG_PTR oldWndProc = SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast(SurfaceWindowProc)); if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS) { mWindowSubclassed = false; return; } - SetProp(mWindow, kSurfaceProperty, reinterpret_cast(this)); - SetProp(mWindow, kParentWndProc, reinterpret_cast(oldWndProc)); + SetProp(window, kSurfaceProperty, reinterpret_cast(this)); + SetProp(window, kParentWndProc, reinterpret_cast(oldWndProc)); mWindowSubclassed = true; -#else - mWindowSubclassed = false; #endif } void Surface::unsubclassWindow() { -#if !defined(ANGLE_PLATFORM_WINRT) if(!mWindowSubclassed) { return; } +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + HWND window = mNativeWindow.getNativeWindow(); + if (!window) + { + return; + } + // un-subclass - LONG_PTR parentWndFunc = reinterpret_cast(GetProp(mWindow, kParentWndProc)); + LONG_PTR parentWndFunc = reinterpret_cast(GetProp(window, kParentWndProc)); // Check the windowproc is still SurfaceWindowProc. // If this assert fails, then it is likely the application has subclassed the @@ -396,29 +329,28 @@ void Surface::unsubclassWindow() // EGL context, or to unsubclass before destroying the EGL context. if(parentWndFunc) { - LONG_PTR prevWndFunc = SetWindowLongPtr(mWindow, GWLP_WNDPROC, parentWndFunc); + LONG_PTR prevWndFunc = SetWindowLongPtr(window, GWLP_WNDPROC, parentWndFunc); UNUSED_ASSERTION_VARIABLE(prevWndFunc); ASSERT(prevWndFunc == reinterpret_cast(SurfaceWindowProc)); } - RemoveProp(mWindow, kSurfaceProperty); - RemoveProp(mWindow, kParentWndProc); - mWindowSubclassed = false; + RemoveProp(window, kSurfaceProperty); + RemoveProp(window, kParentWndProc); #endif + mWindowSubclassed = false; } bool Surface::checkForOutOfDateSwapChain() { + RECT client; int clientWidth = getWidth(); int clientHeight = getHeight(); bool sizeDirty = false; -#if !defined(ANGLE_PLATFORM_WINRT) - if (!mFixedSize && !IsIconic(getWindowHandle())) + if (!mFixedSize && !mNativeWindow.isIconic()) { - RECT client; // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized // because that's not a useful size to render to. - if (!GetClientRect(getWindowHandle(), &client)) + if (!mNativeWindow.getClientRect(&client)) { ASSERT(false); return false; @@ -429,7 +361,13 @@ bool Surface::checkForOutOfDateSwapChain() clientHeight = client.bottom - client.top; sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); } -#endif + + if (mFixedSize && (mWidth != mFixedWidth || mHeight != mFixedHeight)) + { + clientWidth = mFixedWidth; + clientHeight = mFixedHeight; + sizeDirty = true; + } bool wasDirty = (mSwapIntervalDirty || sizeDirty); @@ -455,17 +393,17 @@ bool Surface::checkForOutOfDateSwapChain() return false; } -bool Surface::swap() +Error Surface::swap() { - return swapRect(0, 0, mWidth, mHeight); + return swapRect(0, 0, abs(mWidth), abs(mHeight)); } -bool Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) { if (!mPostSubBufferSupported) { // Spec is not clear about how this should be handled. - return true; + return Error(EGL_SUCCESS); } return swapRect(x, y, width, height); @@ -550,77 +488,18 @@ EGLint Surface::isFixedSize() const return mFixedSize; } +void Surface::setFixedWidth(EGLint width) +{ + mFixedWidth = width; +} + +void Surface::setFixedHeight(EGLint height) +{ + mFixedHeight = height; +} + EGLenum Surface::getFormat() const { return mConfig->mRenderTargetFormat; } - -#if defined(ANGLE_PLATFORM_WINRT) - -HRESULT Surface::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) -{ - HRESULT hr; - Size size; - hr = args->get_Size(&size); - ASSERT(SUCCEEDED(hr)); - - resizeSwapChain(std::floor(size.Width * mScaleFactor + 0.5), - std::floor(size.Height * mScaleFactor + 0.5)); - - if (static_cast(getCurrentDrawSurface()) == this) - { - glMakeCurrent(glGetCurrentContext(), static_cast(getCurrentDisplay()), this); - } - - return S_OK; -} - -HRESULT Surface::onDpiChanged(IDisplayInformation *displayInformation, IInspectable *) -{ - HRESULT hr; -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - ComPtr displayInformation2; - hr = displayInformation->QueryInterface(displayInformation2.GetAddressOf()); - ASSERT(SUCCEEDED(hr)); - - hr = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); - ASSERT(SUCCEEDED(hr)); -# else - ResolutionScale resolutionScale; - hr = displayInformation->get_ResolutionScale(&resolutionScale); - ASSERT(SUCCEEDED(hr)); - - mScaleFactor = double(resolutionScale) / 100.0; -# endif - return S_OK; -} - -# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -HRESULT Surface::onOrientationChanged(IDisplayInformation *displayInformation, IInspectable *) -{ - HRESULT hr; - DisplayOrientations orientation; - hr = displayInformation->get_CurrentOrientation(&orientation); - ASSERT(SUCCEEDED(hr)); - switch (orientation) { - default: - case DisplayOrientations_Portrait: - mSwapFlags = rx::SWAP_NORMAL; - break; - case DisplayOrientations_Landscape: - mSwapFlags = rx::SWAP_ROTATE_90; - break; - case DisplayOrientations_LandscapeFlipped: - mSwapFlags = rx::SWAP_ROTATE_270; - break; - case DisplayOrientations_PortraitFlipped: - mSwapFlags = rx::SWAP_ROTATE_180; - break; - } - return S_OK; -} -# endif - -#endif - } diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h index ebffce8fed..46382d06e1 100644 --- a/src/3rdparty/angle/src/libEGL/Surface.h +++ b/src/3rdparty/angle/src/libEGL/Surface.h @@ -11,23 +11,12 @@ #ifndef LIBEGL_SURFACE_H_ #define LIBEGL_SURFACE_H_ +#include "libEGL/Error.h" + #include #include "common/angleutils.h" - -#if defined(ANGLE_PLATFORM_WINRT) -#include -namespace ABI { namespace Windows { - namespace UI { namespace Core { - struct ICoreWindow; - struct IWindowSizeChangedEventArgs; - } } - namespace Graphics { namespace Display { - struct IDisplayInformation; - } } -} } -struct IInspectable; -#endif +#include "common/NativeWindow.h" namespace gl { @@ -35,8 +24,8 @@ class Texture2D; } namespace rx { -class Renderer; class SwapChain; +class RendererD3D; //TODO(jmadill): remove this } namespace egl @@ -52,13 +41,13 @@ class Surface virtual ~Surface(); - bool initialize(); + Error initialize(); void release(); - bool resetSwapChain(); + Error resetSwapChain(); EGLNativeWindowType getWindowHandle(); - bool swap(); - bool postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); + Error swap(); + Error postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); virtual EGLint isPostSubBufferSupported() const; @@ -81,35 +70,31 @@ class Surface virtual gl::Texture2D *getBoundTexture() const; EGLint isFixedSize() const; + void setFixedWidth(EGLint width); + void setFixedHeight(EGLint height); -private: + private: DISALLOW_COPY_AND_ASSIGN(Surface); -#if defined(ANGLE_PLATFORM_WINRT) - HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); - HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -# endif -#endif - Display *const mDisplay; - rx::Renderer *mRenderer; + rx::RendererD3D *mRenderer; HANDLE mShareHandle; rx::SwapChain *mSwapChain; void subclassWindow(); void unsubclassWindow(); - bool resizeSwapChain(int backbufferWidth, int backbufferHeight); - bool resetSwapChain(int backbufferWidth, int backbufferHeight); - bool swapRect(EGLint x, EGLint y, EGLint width, EGLint height); + Error resizeSwapChain(int backbufferWidth, int backbufferHeight); + Error resetSwapChain(int backbufferWidth, int backbufferHeight); + Error swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - const EGLNativeWindowType mWindow; // Window that the surface is created for. + rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking const egl::Config *mConfig; // EGL config surface was created with EGLint mHeight; // Height of surface EGLint mWidth; // Width of surface + EGLint mFixedHeight; // Pending height of the surface + EGLint mFixedWidth; // Pending width of the surface // EGLint horizontalResolution; // Horizontal dot pitch // EGLint verticalResolution; // Vertical dot pitch // EGLBoolean largestPBuffer; // If true, create largest pbuffer possible @@ -126,18 +111,9 @@ private: EGLint mSwapInterval; EGLint mPostSubBufferSupported; EGLint mFixedSize; - EGLint mSwapFlags; bool mSwapIntervalDirty; gl::Texture2D *mTexture; -#if defined(ANGLE_PLATFORM_WINRT) - double mScaleFactor; - EventRegistrationToken mSizeToken; - EventRegistrationToken mDpiToken; -# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - EventRegistrationToken mOrientationToken; -# endif -#endif }; } diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp index c2e0fd6d3d..68399d63a4 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.cpp +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -13,7 +13,6 @@ #include "common/debug.h" #include "common/version.h" -#include "common/platform.h" #include "libGLESv2/Context.h" #include "libGLESv2/Texture.h" #include "libGLESv2/main.h" @@ -26,16 +25,20 @@ #include "libEGL/Display.h" #include "libEGL/Surface.h" +#include "common/NativeWindow.h" + bool validateDisplay(egl::Display *display) { if (display == EGL_NO_DISPLAY) { - return egl::error(EGL_BAD_DISPLAY, false); + recordError(egl::Error(EGL_BAD_DISPLAY)); + return false; } if (!display->isInitialized()) { - return egl::error(EGL_NOT_INITIALIZED, false); + recordError(egl::Error(EGL_NOT_INITIALIZED)); + return false; } return true; @@ -50,7 +53,8 @@ bool validateConfig(egl::Display *display, EGLConfig config) if (!display->isValidConfig(config)) { - return egl::error(EGL_BAD_CONFIG, false); + recordError(egl::Error(EGL_BAD_CONFIG)); + return false; } return true; @@ -65,7 +69,8 @@ bool validateContext(egl::Display *display, gl::Context *context) if (!display->isValidContext(context)) { - return egl::error(EGL_BAD_CONTEXT, false); + recordError(egl::Error(EGL_BAD_CONTEXT)); + return false; } return true; @@ -80,7 +85,8 @@ bool validateSurface(egl::Display *display, egl::Surface *surface) if (!display->isValidSurface(surface)) { - return egl::error(EGL_BAD_SURFACE, false); + recordError(egl::Error(EGL_BAD_SURFACE)); + return false; } return true; @@ -93,12 +99,7 @@ EGLint __stdcall eglGetError(void) EVENT("()"); EGLint error = egl::getCurrentError(); - - if (error != EGL_SUCCESS) - { - egl::setCurrentError(EGL_SUCCESS); - } - + recordError(egl::Error(EGL_SUCCESS)); return error; } @@ -106,7 +107,7 @@ EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id) { EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id); - return egl::Display::getDisplay(display_id, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + return egl::Display::getDisplay(display_id, egl::AttributeMap()); } EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_display, const EGLint *attrib_list) @@ -120,19 +121,26 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis break; default: - return egl::error(EGL_BAD_CONFIG, EGL_NO_DISPLAY); + recordError(egl::Error(EGL_BAD_CONFIG)); + return EGL_NO_DISPLAY; } EGLNativeDisplayType displayId = static_cast(native_display); -#if !defined(ANGLE_PLATFORM_WINRT) + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) // Validate the display device context if (WindowFromDC(displayId) == NULL) { - return egl::success(EGL_NO_DISPLAY); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; } #endif - EGLint requestedDisplayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + EGLint platformType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; + bool majorVersionSpecified = false; + bool minorVersionSpecified = false; + bool requestedWARP = false; + if (attrib_list) { for (const EGLint *curAttrib = attrib_list; curAttrib[0] != EGL_NONE; curAttrib += 2) @@ -140,7 +148,69 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis switch (curAttrib[0]) { case EGL_PLATFORM_ANGLE_TYPE_ANGLE: - requestedDisplayType = curAttrib[1]; + switch (curAttrib[1]) + { + case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: + break; + + case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: + if (!egl::Display::supportsPlatformD3D()) + { + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; + } + break; + + case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: + case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: + if (!egl::Display::supportsPlatformOpenGL()) + { + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; + } + break; + + default: + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; + } + platformType = curAttrib[1]; + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE: + if (curAttrib[1] != EGL_DONT_CARE) + { + majorVersionSpecified = true; + } + break; + + case EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE: + if (curAttrib[1] != EGL_DONT_CARE) + { + minorVersionSpecified = true; + } + break; + + case EGL_PLATFORM_ANGLE_USE_WARP_ANGLE: + if (!egl::Display::supportsPlatformD3D()) + { + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; + } + + switch (curAttrib[1]) + { + case EGL_FALSE: + case EGL_TRUE: + break; + + default: + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_DISPLAY; + } + + requestedWARP = (curAttrib[1] == EGL_TRUE); break; default: @@ -149,33 +219,20 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis } } - switch (requestedDisplayType) + if (!majorVersionSpecified && minorVersionSpecified) { - case EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE: - break; - - case EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE: - if (!egl::Display::supportsPlatformD3D()) - { - return egl::success(EGL_NO_DISPLAY); - } - break; - - case EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE: - case EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE: - if (!egl::Display::supportsPlatformOpenGL()) - { - return egl::success(EGL_NO_DISPLAY); - } - break; - - default: - return egl::success(EGL_NO_DISPLAY); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; } - return egl::Display::getDisplay(displayId, requestedDisplayType); + if (platformType != EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE && requestedWARP) + { + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_DISPLAY; + } + + recordError(egl::Error(EGL_SUCCESS)); + return egl::Display::getDisplay(displayId, egl::AttributeMap(attrib_list)); } EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) @@ -185,20 +242,24 @@ EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) if (dpy == EGL_NO_DISPLAY) { - return egl::error(EGL_BAD_DISPLAY, EGL_FALSE); + recordError(egl::Error(EGL_BAD_DISPLAY)); + return EGL_FALSE; } egl::Display *display = static_cast(dpy); - if (!display->initialize()) + egl::Error error = display->initialize(); + if (error.isError()) { - return egl::error(EGL_NOT_INITIALIZED, EGL_FALSE); + recordError(error); + return EGL_FALSE; } if (major) *major = 1; if (minor) *minor = 4; - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) @@ -207,14 +268,16 @@ EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) if (dpy == EGL_NO_DISPLAY) { - return egl::error(EGL_BAD_DISPLAY, EGL_FALSE); + recordError(egl::Error(EGL_BAD_DISPLAY)); + return EGL_FALSE; } egl::Display *display = static_cast(dpy); display->terminate(); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) @@ -227,19 +290,28 @@ const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) return NULL; } + const char *result; switch (name) { case EGL_CLIENT_APIS: - return egl::success("OpenGL_ES"); + result = "OpenGL_ES"; + break; case EGL_EXTENSIONS: - return egl::success(egl::Display::getExtensionString(display)); + result = egl::Display::getExtensionString(display); + break; case EGL_VENDOR: - return egl::success(display->getVendorString()); + result = display->getVendorString(); + break; case EGL_VERSION: - return egl::success("1.4 (ANGLE " ANGLE_VERSION_STRING ")"); + result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")"; + break; default: - return egl::error(EGL_BAD_PARAMETER, (const char*)NULL); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return NULL; } + + recordError(egl::Error(EGL_SUCCESS)); + return result; } EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) @@ -257,17 +329,20 @@ EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint co if (!num_config) { - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } const EGLint attribList[] = {EGL_NONE}; if (!display->getConfigs(configs, attribList, config_size, num_config)) { - return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) @@ -285,7 +360,8 @@ EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, if (!num_config) { - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } const EGLint attribList[] = {EGL_NONE}; @@ -297,7 +373,8 @@ EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, display->getConfigs(configs, attrib_list, config_size, num_config); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) @@ -314,10 +391,12 @@ EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint if (!display->getConfigAttrib(config, attribute, value)) { - return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) @@ -332,16 +411,21 @@ EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EG return EGL_NO_SURFACE; } -#if !defined(ANGLE_PLATFORM_WINRT) - HWND window = (HWND)win; - - if (!IsWindow(window)) + if (!rx::IsValidEGLNativeWindowType(win)) { - return egl::error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + recordError(egl::Error(EGL_BAD_NATIVE_WINDOW)); + return EGL_NO_SURFACE; } -#endif - return display->createWindowSurface(win, config, attrib_list); + EGLSurface surface = EGL_NO_SURFACE; + egl::Error error = display->createWindowSurface(win, config, attrib_list, &surface); + if (error.isError()) + { + recordError(error); + return EGL_NO_SURFACE; + } + + return surface; } EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) @@ -356,7 +440,15 @@ EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, c return EGL_NO_SURFACE; } - return display->createOffscreenSurface(config, NULL, attrib_list); + EGLSurface surface = EGL_NO_SURFACE; + egl::Error error = display->createOffscreenSurface(config, NULL, attrib_list, &surface); + if (error.isError()) + { + recordError(error); + return EGL_NO_SURFACE; + } + + return surface; } EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) @@ -373,7 +465,8 @@ EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EG UNIMPLEMENTED(); // FIXME - return egl::success(EGL_NO_SURFACE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_NO_SURFACE; } EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) @@ -390,12 +483,14 @@ EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) if (surface == EGL_NO_SURFACE) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } display->destroySurface((egl::Surface*)surface); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) @@ -413,7 +508,8 @@ EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint if (surface == EGL_NO_SURFACE) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } switch (attribute) @@ -473,10 +569,12 @@ EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint *value = eglSurface->isFixedSize(); break; default: - return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value) @@ -498,7 +596,8 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf if (surface == EGL_NO_SURFACE) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } rx::SwapChain *swapchain = eglSurface->getSwapChain(); @@ -522,7 +621,8 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf if (renderer->getMajorShaderModel() < 4) { - return egl::error(EGL_BAD_CONTEXT, EGL_FALSE); + recordError(egl::Error(EGL_BAD_CONTEXT)); + return EGL_FALSE; } *value = static_cast(renderer)->getDevice(); @@ -530,10 +630,12 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf break; #endif default: - return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglBindAPI(EGLenum api) @@ -544,16 +646,19 @@ EGLBoolean __stdcall eglBindAPI(EGLenum api) { case EGL_OPENGL_API: case EGL_OPENVG_API: - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; // Not supported by this implementation case EGL_OPENGL_ES_API: break; default: - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } egl::setCurrentAPI(api); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLenum __stdcall eglQueryAPI(void) @@ -562,7 +667,8 @@ EGLenum __stdcall eglQueryAPI(void) EGLenum API = egl::getCurrentAPI(); - return egl::success(API); + recordError(egl::Error(EGL_SUCCESS)); + return API; } EGLBoolean __stdcall eglWaitClient(void) @@ -571,7 +677,8 @@ EGLBoolean __stdcall eglWaitClient(void) UNIMPLEMENTED(); // FIXME - return egl::success(0); + recordError(egl::Error(EGL_SUCCESS)); + return 0; } EGLBoolean __stdcall eglReleaseThread(void) @@ -580,7 +687,8 @@ EGLBoolean __stdcall eglReleaseThread(void) eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) @@ -598,10 +706,19 @@ EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum bu if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer) { - return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_NO_SURFACE; } - return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list); + EGLSurface surface = EGL_NO_SURFACE; + egl::Error error = display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list, &surface); + if (error.isError()) + { + recordError(error); + return EGL_NO_SURFACE; + } + + return surface; } EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) @@ -617,9 +734,30 @@ EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint return EGL_FALSE; } + switch (attribute) + { + case EGL_WIDTH: + if (!eglSurface->isFixedSize() || !value) { + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + eglSurface->setFixedWidth(value); + return EGL_TRUE; + case EGL_HEIGHT: + if (!eglSurface->isFixedSize() || !value) { + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; + } + eglSurface->setFixedHeight(value); + return EGL_TRUE; + default: + break; + } + UNIMPLEMENTED(); // FIXME - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) @@ -636,30 +774,36 @@ EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint if (buffer != EGL_BACK_BUFFER) { - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } if (eglSurface->getBoundTexture()) { - return egl::error(EGL_BAD_ACCESS, EGL_FALSE); + recordError(egl::Error(EGL_BAD_ACCESS)); + return EGL_FALSE; } if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) { - return egl::error(EGL_BAD_MATCH, EGL_FALSE); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_FALSE; } if (!glBindTexImage(eglSurface)) { - return egl::error(EGL_BAD_MATCH, EGL_FALSE); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_FALSE; } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) @@ -676,17 +820,20 @@ EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLi if (buffer != EGL_BACK_BUFFER) { - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle()) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE) { - return egl::error(EGL_BAD_MATCH, EGL_FALSE); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_FALSE; } gl::Texture2D *texture = eglSurface->getBoundTexture(); @@ -696,7 +843,8 @@ EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLi texture->releaseTexImage(); } - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) @@ -714,12 +862,14 @@ EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) if (draw_surface == NULL) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } draw_surface->setSwapInterval(interval); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) @@ -744,27 +894,38 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte case EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: if (attribute[1] == EGL_TRUE) { - return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); // Unimplemented + recordError(egl::Error(EGL_BAD_CONFIG)); // Unimplemented + return EGL_NO_CONTEXT; // robust_access = true; } else if (attribute[1] != EGL_FALSE) - return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + { + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_CONTEXT; + } break; case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT: if (attribute[1] == EGL_LOSE_CONTEXT_ON_RESET_EXT) + { reset_notification = true; + } else if (attribute[1] != EGL_NO_RESET_NOTIFICATION_EXT) - return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + { + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_CONTEXT; + } break; default: - return egl::error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_NO_CONTEXT; } } } if (client_version != 2 && client_version != 3) { - return egl::error(EGL_BAD_CONFIG, EGL_NO_CONTEXT); + recordError(egl::Error(EGL_BAD_CONFIG)); + return EGL_NO_CONTEXT; } egl::Display *display = static_cast(dpy); @@ -775,18 +936,21 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte if (sharedGLContext->isResetNotificationEnabled() != reset_notification) { - return egl::error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_NO_CONTEXT; } if (sharedGLContext->getClientVersion() != client_version) { - return egl::error(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); + recordError(egl::Error(EGL_BAD_CONTEXT)); + return EGL_NO_CONTEXT; } // Can not share contexts between displays if (sharedGLContext->getRenderer() != display->getRenderer()) { - return egl::error(EGL_BAD_MATCH, EGL_NO_CONTEXT); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_NO_CONTEXT; } } @@ -795,7 +959,16 @@ EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLConte return EGL_NO_CONTEXT; } - return display->createContext(config, client_version, static_cast(share_context), reset_notification, robust_access); + EGLContext context = EGL_NO_CONTEXT; + egl::Error error = display->createContext(config, client_version, static_cast(share_context), + reset_notification, robust_access, &context); + if (error.isError()) + { + recordError(error); + return EGL_NO_CONTEXT; + } + + return context; } EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) @@ -812,12 +985,14 @@ EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) if (ctx == EGL_NO_CONTEXT) { - return egl::error(EGL_BAD_CONTEXT, EGL_FALSE); + recordError(egl::Error(EGL_BAD_CONTEXT)); + return EGL_FALSE; } display->destroyContext(context); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) @@ -832,7 +1007,8 @@ EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface bool noSurface = (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE); if (noContext != noSurface) { - return egl::error(EGL_BAD_MATCH, EGL_FALSE); + recordError(egl::Error(EGL_BAD_MATCH)); + return EGL_FALSE; } if (ctx != EGL_NO_CONTEXT && !validateContext(display, context)) @@ -850,7 +1026,8 @@ EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface if (renderer->isDeviceLost()) { - return egl::error(EGL_CONTEXT_LOST, EGL_FALSE); + recordError(egl::Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; } } @@ -871,7 +1048,8 @@ EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface glMakeCurrent(context, display, static_cast(draw)); - return egl::success(EGL_TRUE); + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLContext __stdcall eglGetCurrentContext(void) @@ -880,7 +1058,8 @@ EGLContext __stdcall eglGetCurrentContext(void) EGLContext context = glGetCurrentContext(); - return egl::success(context); + recordError(egl::Error(EGL_SUCCESS)); + return context; } EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) @@ -889,17 +1068,18 @@ EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) if (readdraw == EGL_READ) { - EGLSurface read = egl::getCurrentReadSurface(); - return egl::success(read); + recordError(egl::Error(EGL_SUCCESS)); + return egl::getCurrentReadSurface(); } else if (readdraw == EGL_DRAW) { - EGLSurface draw = egl::getCurrentDrawSurface(); - return egl::success(draw); + recordError(egl::Error(EGL_SUCCESS)); + return egl::getCurrentDrawSurface(); } else { - return egl::error(EGL_BAD_PARAMETER, EGL_NO_SURFACE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_NO_SURFACE; } } @@ -909,7 +1089,8 @@ EGLDisplay __stdcall eglGetCurrentDisplay(void) EGLDisplay dpy = egl::getCurrentDisplay(); - return egl::success(dpy); + recordError(egl::Error(EGL_SUCCESS)); + return dpy; } EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) @@ -927,7 +1108,8 @@ EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attr UNIMPLEMENTED(); // FIXME - return egl::success(0); + recordError(egl::Error(EGL_SUCCESS)); + return 0; } EGLBoolean __stdcall eglWaitGL(void) @@ -936,7 +1118,8 @@ EGLBoolean __stdcall eglWaitGL(void) UNIMPLEMENTED(); // FIXME - return egl::success(0); + recordError(egl::Error(EGL_SUCCESS)); + return 0; } EGLBoolean __stdcall eglWaitNative(EGLint engine) @@ -945,7 +1128,8 @@ EGLBoolean __stdcall eglWaitNative(EGLint engine) UNIMPLEMENTED(); // FIXME - return egl::success(0); + recordError(egl::Error(EGL_SUCCESS)); + return 0; } EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) @@ -962,20 +1146,25 @@ EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) if (display->getRenderer()->isDeviceLost()) { - return egl::error(EGL_CONTEXT_LOST, EGL_FALSE); + recordError(egl::Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } - if (eglSurface->swap()) + egl::Error error = eglSurface->swap(); + if (error.isError()) { - return egl::success(EGL_TRUE); + recordError(error); + return EGL_FALSE; } - return EGL_FALSE; + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) @@ -992,12 +1181,14 @@ EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativ if (display->getRenderer()->isDeviceLost()) { - return egl::error(EGL_CONTEXT_LOST, EGL_FALSE); + recordError(egl::Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; } UNIMPLEMENTED(); // FIXME - return egl::success(0); + recordError(egl::Error(EGL_SUCCESS)); + return 0; } EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) @@ -1006,7 +1197,8 @@ EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLi if (x < 0 || y < 0 || width < 0 || height < 0) { - return egl::error(EGL_BAD_PARAMETER, EGL_FALSE); + recordError(egl::Error(EGL_BAD_PARAMETER)); + return EGL_FALSE; } egl::Display *display = static_cast(dpy); @@ -1019,20 +1211,25 @@ EGLBoolean __stdcall eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLi if (display->getRenderer()->isDeviceLost()) { - return egl::error(EGL_CONTEXT_LOST, EGL_FALSE); + recordError(egl::Error(EGL_CONTEXT_LOST)); + return EGL_FALSE; } if (surface == EGL_NO_SURFACE) { - return egl::error(EGL_BAD_SURFACE, EGL_FALSE); + recordError(egl::Error(EGL_BAD_SURFACE)); + return EGL_FALSE; } - if (eglSurface->postSubBuffer(x, y, width, height)) + egl::Error error = eglSurface->postSubBuffer(x, y, width, height); + if (error.isError()) { - return egl::success(EGL_TRUE); + recordError(error); + return EGL_FALSE; } - return EGL_FALSE; + recordError(egl::Error(EGL_SUCCESS)); + return EGL_TRUE; } __eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname) diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp index e74737eaba..e88cad775f 100644 --- a/src/3rdparty/angle/src/libEGL/main.cpp +++ b/src/3rdparty/angle/src/libEGL/main.cpp @@ -11,9 +11,6 @@ #include "common/debug.h" #include "common/tls.h" -#if defined(ANGLE_PLATFORM_WINRT) -__declspec(thread) -#endif static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; namespace egl @@ -21,12 +18,6 @@ namespace egl Current *AllocateCurrent() { -#if defined(ANGLE_PLATFORM_WINRT) - if (currentTLS == TLS_OUT_OF_INDEXES) - { - currentTLS = CreateTLSIndex(); - } -#endif ASSERT(currentTLS != TLS_OUT_OF_INDEXES); if (currentTLS == TLS_OUT_OF_INDEXES) { @@ -51,12 +42,6 @@ Current *AllocateCurrent() void DeallocateCurrent() { -#if defined(ANGLE_PLATFORM_WINRT) - if (currentTLS == TLS_OUT_OF_INDEXES) - { - return; - } -#endif Current *current = reinterpret_cast(GetTLSValue(currentTLS)); SafeDelete(current); SetTLSValue(currentTLS, NULL); @@ -72,7 +57,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved { case DLL_PROCESS_ATTACH: { -#if defined(ANGLE_ENABLE_TRACE) +#if defined(ANGLE_ENABLE_DEBUG_TRACE) FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt"); if (debug) @@ -87,15 +72,15 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved } #endif -#if defined(ANGLE_PLATFORM_WINRT) // On WinRT, don't handle TLS from DllMain - return DisableThreadLibraryCalls(instance); -#endif - currentTLS = CreateTLSIndex(); if (currentTLS == TLS_OUT_OF_INDEXES) { return FALSE; } + +#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS + gl::InitializeDebugAnnotations(); +#endif } // Fall through to initialize index case DLL_THREAD_ATTACH: @@ -105,15 +90,17 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved break; case DLL_THREAD_DETACH: { -#if !defined(ANGLE_PLATFORM_WINRT) egl::DeallocateCurrent(); -#endif } break; case DLL_PROCESS_DETACH: { egl::DeallocateCurrent(); DestroyTLSIndex(currentTLS); + +#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS + gl::UninitializeDebugAnnotations(); +#endif } break; default: @@ -143,11 +130,11 @@ Current *GetCurrentData() #endif } -void setCurrentError(EGLint error) +void recordError(const Error &error) { Current *current = GetCurrentData(); - current->error = error; + current->error = error.getCode(); } EGLint getCurrentError() @@ -213,9 +200,4 @@ EGLSurface getCurrentReadSurface() return current->readSurface; } -void error(EGLint errorCode) -{ - egl::setCurrentError(errorCode); -} - } diff --git a/src/3rdparty/angle/src/libEGL/main.h b/src/3rdparty/angle/src/libEGL/main.h index 07f5b9e675..e5361a4a5e 100644 --- a/src/3rdparty/angle/src/libEGL/main.h +++ b/src/3rdparty/angle/src/libEGL/main.h @@ -9,6 +9,8 @@ #ifndef LIBEGL_MAIN_H_ #define LIBEGL_MAIN_H_ +#include "libEGL/Error.h" + #include #include @@ -23,7 +25,7 @@ struct Current EGLSurface readSurface; }; -void setCurrentError(EGLint error); +void recordError(const Error &error); EGLint getCurrentError(); void setCurrentAPI(EGLenum API); @@ -38,24 +40,6 @@ EGLSurface getCurrentDrawSurface(); void setCurrentReadSurface(EGLSurface surface); EGLSurface getCurrentReadSurface(); -void error(EGLint errorCode); - -template -const T &error(EGLint errorCode, const T &returnValue) -{ - error(errorCode); - - return returnValue; -} - -template -const T &success(const T &returnValue) -{ - egl::setCurrentError(EGL_SUCCESS); - - return returnValue; -} - } #endif // LIBEGL_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h index 4d7dde04e1..4f7f5f2c85 100644 --- a/src/3rdparty/angle/src/libGLESv2/BinaryStream.h +++ b/src/3rdparty/angle/src/libGLESv2/BinaryStream.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace gl { @@ -26,7 +27,7 @@ class BinaryInputStream { mError = false; mOffset = 0; - mData = static_cast(data); + mData = static_cast(data); mLength = length; } @@ -85,7 +86,7 @@ class BinaryInputStream return; } - v->assign(mData + mOffset, length); + v->assign(reinterpret_cast(mData) + mOffset, length); mOffset += length; } @@ -115,11 +116,16 @@ class BinaryInputStream return mOffset == mLength; } + const uint8_t *data() + { + return mData; + } + private: DISALLOW_COPY_AND_ASSIGN(BinaryInputStream); bool mError; size_t mOffset; - const char *mData; + const uint8_t *mData; size_t mLength; template diff --git a/src/3rdparty/angle/src/libGLESv2/Buffer.h b/src/3rdparty/angle/src/libGLESv2/Buffer.h index 35a6767502..daa862ca0d 100644 --- a/src/3rdparty/angle/src/libGLESv2/Buffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Buffer.h @@ -19,7 +19,6 @@ namespace rx { -class Renderer; class BufferImpl; }; diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp index 5342de1331..b87689cd3f 100644 --- a/src/3rdparty/angle/src/libGLESv2/Context.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp @@ -9,10 +9,8 @@ #include "libGLESv2/Context.h" -#include "libGLESv2/main.h" #include "common/utilities.h" #include "common/platform.h" -#include "libGLESv2/formatutils.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Fence.h" #include "libGLESv2/Framebuffer.h" @@ -21,14 +19,15 @@ #include "libGLESv2/Program.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Query.h" -#include "libGLESv2/Texture.h" #include "libGLESv2/ResourceManager.h" -#include "libGLESv2/renderer/d3d/IndexDataManager.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/VertexArray.h" #include "libGLESv2/Sampler.h" -#include "libGLESv2/validationES.h" +#include "libGLESv2/Texture.h" #include "libGLESv2/TransformFeedback.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/formatutils.h" +#include "libGLESv2/main.h" +#include "libGLESv2/validationES.h" +#include "libGLESv2/renderer/Renderer.h" #include "libEGL/Surface.h" @@ -38,7 +37,7 @@ namespace gl { -Context::Context(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) +Context::Context(int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess) : mRenderer(renderer) { ASSERT(robustAccess == false); // Unimplemented @@ -66,22 +65,24 @@ Context::Context(int clientVersion, const gl::Context *shareContext, rx::Rendere // In order that access to these initial textures not be lost, they are treated as texture // objects all of whose names are 0. - mZeroTextures[GL_TEXTURE_2D].set(new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), 0)); - bindTexture(GL_TEXTURE_2D, 0); + Texture2D *zeroTexture2D = new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), 0); + mZeroTextures[GL_TEXTURE_2D].set(zeroTexture2D); - mZeroTextures[GL_TEXTURE_CUBE_MAP].set(new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0)); - bindTexture(GL_TEXTURE_CUBE_MAP, 0); + TextureCubeMap *zeroTextureCube = new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), 0); + mZeroTextures[GL_TEXTURE_CUBE_MAP].set(zeroTextureCube); if (mClientVersion >= 3) { // TODO: These could also be enabled via extension - mZeroTextures[GL_TEXTURE_3D].set(new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), 0)); - bindTexture(GL_TEXTURE_3D, 0); + Texture3D *zeroTexture3D = new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), 0); + mZeroTextures[GL_TEXTURE_3D].set(zeroTexture3D); - mZeroTextures[GL_TEXTURE_2D_ARRAY].set(new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0)); - bindTexture(GL_TEXTURE_2D_ARRAY, 0); + Texture2DArray *zeroTexture2DArray = new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), 0); + mZeroTextures[GL_TEXTURE_2D_ARRAY].set(zeroTexture2DArray); } + mState.initializeZeroTextures(mZeroTextures); + bindVertexArray(0); bindArrayBuffer(0); bindElementArrayBuffer(0); @@ -91,13 +92,13 @@ Context::Context(int clientVersion, const gl::Context *shareContext, rx::Rendere bindRenderbuffer(0); bindGenericUniformBuffer(0); - for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++) { bindIndexedUniformBuffer(0, i, 0, -1); } bindGenericTransformFeedbackBuffer(0); - for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++) { bindIndexedTransformFeedbackBuffer(0, i, 0, -1); } @@ -119,8 +120,6 @@ Context::Context(int clientVersion, const gl::Context *shareContext, rx::Rendere mResetStatus = GL_NO_ERROR; mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT); mRobustAccess = robustAccess; - - mState.setContext(this); } Context::~Context() @@ -175,7 +174,10 @@ Context::~Context() } mZeroTextures.clear(); - mResourceManager->release(); + if (mResourceManager) + { + mResourceManager->release(); + } } void Context::makeCurrent(egl::Surface *surface) @@ -194,14 +196,11 @@ void Context::makeCurrent(egl::Surface *surface) // Wrap the existing swapchain resources into GL objects and assign them to the '0' names rx::SwapChain *swapchain = surface->getSwapChain(); - Colorbuffer *colorbufferZero = new Colorbuffer(mRenderer, swapchain); - DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(mRenderer, swapchain); - Framebuffer *framebufferZero = new DefaultFramebuffer(mRenderer, colorbufferZero, depthStencilbufferZero); + rx::RenderbufferImpl *colorbufferZero = mRenderer->createRenderbuffer(swapchain, false); + rx::RenderbufferImpl *depthStencilbufferZero = mRenderer->createRenderbuffer(swapchain, true); + Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero); setFramebufferZero(framebufferZero); - - // Store the current client version in the renderer - mRenderer->setCurrentClientVersion(mClientVersion); } // NOTE: this function should not assume that this context is current! @@ -229,7 +228,7 @@ GLuint Context::createProgram() GLuint Context::createShader(GLenum type) { - return mResourceManager->createShader(type); + return mResourceManager->createShader(getData(), type); } GLuint Context::createTexture() @@ -242,15 +241,10 @@ GLuint Context::createRenderbuffer() return mResourceManager->createRenderbuffer(); } -GLsync Context::createFenceSync(GLenum condition) +GLsync Context::createFenceSync() { GLuint handle = mResourceManager->createFenceSync(); - gl::FenceSync *fenceSync = mResourceManager->getFenceSync(handle); - ASSERT(fenceSync); - - fenceSync->set(condition); - return reinterpret_cast(handle); } @@ -294,7 +288,7 @@ GLuint Context::createFenceNV() { GLuint handle = mFenceNVHandleAllocator.allocate(); - mFenceNVMap[handle] = new FenceNV(mRenderer); + mFenceNVMap[handle] = new FenceNV(mRenderer->createFenceNV()); return handle; } @@ -355,12 +349,12 @@ void Context::deleteFenceSync(GLsync fenceSync) // wait commands finish. However, since the name becomes invalid, we cannot query the fence, // and since our API is currently designed for being called from a single thread, we can delete // the fence immediately. - mResourceManager->deleteFenceSync(uintptr_t(fenceSync)); + mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); } void Context::deleteVertexArray(GLuint vertexArray) { - auto vertexArrayObject = mVertexArrayMap.find(vertexArray); + VertexArrayMap::iterator vertexArrayObject = mVertexArrayMap.find(vertexArray); if (vertexArrayObject != mVertexArrayMap.end()) { @@ -461,12 +455,12 @@ Renderbuffer *Context::getRenderbuffer(GLuint handle) FenceSync *Context::getFenceSync(GLsync handle) const { - return mResourceManager->getFenceSync(uintptr_t(handle)); + return mResourceManager->getFenceSync(reinterpret_cast(handle)); } VertexArray *Context::getVertexArray(GLuint handle) const { - auto vertexArray = mVertexArrayMap.find(handle); + VertexArrayMap::const_iterator vertexArray = mVertexArrayMap.find(handle); if (vertexArray == mVertexArrayMap.end()) { @@ -515,18 +509,30 @@ void Context::bindElementArrayBuffer(unsigned int buffer) mState.getVertexArray()->setElementArrayBuffer(getBuffer(buffer)); } -void Context::bindTexture(GLenum target, GLuint texture) +void Context::bindTexture(GLenum target, GLuint handle) { - mResourceManager->checkTextureAllocation(texture, target); + Texture *texture = NULL; - mState.setSamplerTexture(target, getTexture(texture)); + if (handle == 0) + { + texture = mZeroTextures[target].get(); + } + else + { + mResourceManager->checkTextureAllocation(handle, target); + texture = getTexture(handle); + } + + ASSERT(texture); + + mState.setSamplerTexture(target, texture); } void Context::bindReadFramebuffer(GLuint framebuffer) { if (!getFramebuffer(framebuffer)) { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); + mFramebufferMap[framebuffer] = new Framebuffer(framebuffer); } mState.setReadFramebufferBinding(getFramebuffer(framebuffer)); @@ -536,7 +542,7 @@ void Context::bindDrawFramebuffer(GLuint framebuffer) { if (!getFramebuffer(framebuffer)) { - mFramebufferMap[framebuffer] = new Framebuffer(mRenderer, framebuffer); + mFramebufferMap[framebuffer] = new Framebuffer(framebuffer); } mState.setDrawFramebufferBinding(getFramebuffer(framebuffer)); @@ -640,33 +646,44 @@ void Context::useProgram(GLuint program) } } -void Context::linkProgram(GLuint program) +Error Context::linkProgram(GLuint program) { Program *programObject = mResourceManager->getProgram(program); - bool linked = programObject->link(getCaps()); + Error error = programObject->link(getData()); + if (error.isError()) + { + return error; + } // if the current program was relinked successfully we // need to install the new executables - if (linked && program == mState.getCurrentProgramId()) + if (programObject->isLinked() && program == mState.getCurrentProgramId()) { mState.setCurrentProgramBinary(programObject->getProgramBinary()); } + + return Error(GL_NO_ERROR); } -void Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length) +Error Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { Program *programObject = mResourceManager->getProgram(program); - bool loaded = programObject->setProgramBinary(binaryFormat, binary, length); + Error error = programObject->setProgramBinary(binaryFormat, binary, length); + if (error.isError()) + { + return error; + } // if the current program was reloaded successfully we // need to install the new executables - if (loaded && program == mState.getCurrentProgramId()) + if (programObject->isLinked() && program == mState.getCurrentProgramId()) { mState.setCurrentProgramBinary(programObject->getProgramBinary()); } + return Error(GL_NO_ERROR); } void Context::bindTransformFeedback(GLuint transformFeedback) @@ -724,33 +741,6 @@ void Context::setFramebufferZero(Framebuffer *buffer) mFramebufferMap[0] = buffer; } -void Context::setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) -{ - ASSERT(getTextureCaps().get(internalformat).renderable); - - RenderbufferStorage *renderbuffer = NULL; - - const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); - if (formatInfo.depthBits > 0 && formatInfo.stencilBits > 0) - { - renderbuffer = new gl::DepthStencilbuffer(mRenderer, width, height, samples); - } - else if (formatInfo.depthBits > 0) - { - renderbuffer = new gl::Depthbuffer(mRenderer, width, height, samples); - } - else if (formatInfo.stencilBits > 0) - { - renderbuffer = new gl::Stencilbuffer(mRenderer, width, height, samples); - } - else - { - renderbuffer = new gl::Colorbuffer(mRenderer, width, height, internalformat, samples); - } - - mState.getCurrentRenderbuffer()->setStorage(renderbuffer); -} - Framebuffer *Context::getFramebuffer(unsigned int handle) const { FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle); @@ -837,14 +827,7 @@ Texture2DArray *Context::getTexture2DArray() const Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const { - if (mState.getSamplerTextureId(sampler, type) == 0) - { - return mZeroTextures.at(type).get(); - } - else - { - return mState.getSamplerTexture(sampler, type); - } + return mState.getSamplerTexture(sampler, type); } void Context::getBooleanv(GLenum pname, GLboolean *params) @@ -962,7 +945,7 @@ void Context::getIntegerv(GLenum pname, GLint *params) *params = static_cast(mExtensionStrings.size()); break; default: - mState.getIntegerv(pname, params); + mState.getIntegerv(getData(), pname, params); break; } } @@ -1309,309 +1292,6 @@ bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned return false; } -// Applies the render target surface, depth stencil surface, viewport rectangle and -// scissor rectangle to the renderer -Error Context::applyRenderTarget(GLenum drawMode, bool ignoreViewport) -{ - Framebuffer *framebufferObject = mState.getDrawFramebuffer(); - ASSERT(framebufferObject && framebufferObject->completeness() == GL_FRAMEBUFFER_COMPLETE); - - gl::Error error = mRenderer->applyRenderTarget(framebufferObject); - if (error.isError()) - { - return error; - } - - float nearZ, farZ; - mState.getDepthRange(&nearZ, &farZ); - mRenderer->setViewport(mState.getViewport(), nearZ, farZ, drawMode, mState.getRasterizerState().frontFace, - ignoreViewport); - - mRenderer->setScissorRectangle(mState.getScissor(), mState.isScissorTestEnabled()); - - return gl::Error(GL_NO_ERROR); -} - -// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device -Error Context::applyState(GLenum drawMode) -{ - Framebuffer *framebufferObject = mState.getDrawFramebuffer(); - int samples = framebufferObject->getSamples(); - - RasterizerState rasterizer = mState.getRasterizerState(); - rasterizer.pointDrawMode = (drawMode == GL_POINTS); - rasterizer.multiSample = (samples != 0); - - Error error = mRenderer->setRasterizerState(rasterizer); - if (error.isError()) - { - return error; - } - - unsigned int mask = 0; - if (mState.isSampleCoverageEnabled()) - { - GLclampf coverageValue; - bool coverageInvert = false; - mState.getSampleCoverageParams(&coverageValue, &coverageInvert); - if (coverageValue != 0) - { - float threshold = 0.5f; - - for (int i = 0; i < samples; ++i) - { - mask <<= 1; - - if ((i + 1) * coverageValue >= threshold) - { - threshold += 1.0f; - mask |= 1; - } - } - } - - if (coverageInvert) - { - mask = ~mask; - } - } - else - { - mask = 0xFFFFFFFF; - } - error = mRenderer->setBlendState(framebufferObject, mState.getBlendState(), mState.getBlendColor(), mask); - if (error.isError()) - { - return error; - } - - error = mRenderer->setDepthStencilState(mState.getDepthStencilState(), mState.getStencilRef(), mState.getStencilBackRef(), - rasterizer.frontFace == GL_CCW); - if (error.isError()) - { - return error; - } - - return Error(GL_NO_ERROR); -} - -// Applies the shaders and shader constants to the Direct3D 9 device -Error Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive) -{ - const VertexAttribute *vertexAttributes = mState.getVertexArray()->getVertexAttributes(); - - VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]; - VertexFormat::GetInputLayout(inputLayout, programBinary, vertexAttributes, mState.getVertexAttribCurrentValues()); - - const Framebuffer *fbo = mState.getDrawFramebuffer(); - - Error error = mRenderer->applyShaders(programBinary, inputLayout, fbo, mState.getRasterizerState().rasterizerDiscard, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - return programBinary->applyUniforms(); -} - -Error Context::generateSwizzles(ProgramBinary *programBinary, SamplerType type) -{ - size_t samplerRange = programBinary->getUsedSamplerRange(type); - - for (size_t i = 0; i < samplerRange; i++) - { - GLenum textureType = programBinary->getSamplerTextureType(type, i); - GLint textureUnit = programBinary->getSamplerMapping(type, i, getCaps()); - if (textureUnit != -1) - { - Texture* texture = getSamplerTexture(textureUnit, textureType); - if (texture->getSamplerState().swizzleRequired()) - { - Error error = mRenderer->generateSwizzle(texture); - if (error.isError()) - { - return error; - } - } - } - } - - return Error(GL_NO_ERROR); -} - -Error Context::generateSwizzles(ProgramBinary *programBinary) -{ - Error error = generateSwizzles(programBinary, SAMPLER_VERTEX); - if (error.isError()) - { - return error; - } - - error = generateSwizzles(programBinary, SAMPLER_PIXEL); - if (error.isError()) - { - return error; - } - - return Error(GL_NO_ERROR); -} - -// For each Direct3D sampler of either the pixel or vertex stage, -// looks up the corresponding OpenGL texture image unit and texture type, -// and sets the texture and its addressing/filtering state (or NULL when inactive). -Error Context::applyTextures(ProgramBinary *programBinary, SamplerType shaderType, - const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount) -{ - size_t samplerRange = programBinary->getUsedSamplerRange(shaderType); - for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) - { - GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex); - GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, getCaps()); - if (textureUnit != -1) - { - SamplerState sampler; - Texture* texture = getSamplerTexture(textureUnit, textureType); - texture->getSamplerStateWithNativeOffset(&sampler); - - Sampler *samplerObject = mState.getSampler(textureUnit); - if (samplerObject) - { - samplerObject->getState(&sampler); - } - - // TODO: std::binary_search may become unavailable using older versions of GCC - if (texture->isSamplerComplete(sampler, mTextureCaps, mExtensions, mClientVersion) && - !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) - { - Error error = mRenderer->setSamplerState(shaderType, samplerIndex, sampler); - if (error.isError()) - { - return error; - } - - error = mRenderer->setTexture(shaderType, samplerIndex, texture); - if (error.isError()) - { - return error; - } - } - else - { - // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. - Texture *incompleteTexture = getIncompleteTexture(textureType); - gl::Error error = mRenderer->setTexture(shaderType, samplerIndex, incompleteTexture); - if (error.isError()) - { - return error; - } - } - } - else - { - // No texture bound to this slot even though it is used by the shader, bind a NULL texture - Error error = mRenderer->setTexture(shaderType, samplerIndex, NULL); - if (error.isError()) - { - return error; - } - } - } - - // Set all the remaining textures to NULL - size_t samplerCount = (shaderType == SAMPLER_PIXEL) ? mCaps.maxTextureImageUnits - : mCaps.maxVertexTextureImageUnits; - for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) - { - Error error = mRenderer->setTexture(shaderType, samplerIndex, NULL); - if (error.isError()) - { - return error; - } - } - - return Error(GL_NO_ERROR); -} - -Error Context::applyTextures(ProgramBinary *programBinary) -{ - FramebufferTextureSerialArray framebufferSerials; - size_t framebufferSerialCount = getBoundFramebufferTextureSerials(&framebufferSerials); - - Error error = applyTextures(programBinary, SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - error = applyTextures(programBinary, SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount); - if (error.isError()) - { - return error; - } - - return Error(GL_NO_ERROR); -} - -Error Context::applyUniformBuffers() -{ - Program *programObject = getProgram(mState.getCurrentProgramId()); - ProgramBinary *programBinary = programObject->getProgramBinary(); - - std::vector boundBuffers; - - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++) - { - GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex); - - if (mState.getIndexedUniformBuffer(blockBinding)->id() == 0) - { - // undefined behaviour - return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."); - } - else - { - Buffer *uniformBuffer = mState.getIndexedUniformBuffer(blockBinding); - ASSERT(uniformBuffer); - boundBuffers.push_back(uniformBuffer); - } - } - - return programBinary->applyUniformBuffers(boundBuffers, getCaps()); -} - -bool Context::applyTransformFeedbackBuffers() -{ - TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback(); - if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) - { - Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - transformFeedbackBuffers[i] = mState.getIndexedTransformFeedbackBuffer(i); - transformFeedbackOffsets[i] = mState.getIndexedTransformFeedbackBufferOffset(i); - } - mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets); - return true; - } - else - { - return false; - } -} - -void Context::markTransformFeedbackUsage() -{ - for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) - { - Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i); - if (buffer) - { - buffer->markTransformFeedbackUsage(); - } - } -} - Error Context::clear(GLbitfield mask) { if (mState.isRasterizerDiscardEnabled()) @@ -1619,290 +1299,71 @@ Error Context::clear(GLbitfield mask) return Error(GL_NO_ERROR); } - ClearParameters clearParams = mState.getClearParameters(mask); - - applyRenderTarget(GL_TRIANGLES, true); // Clips the clear to the scissor rectangle but not the viewport - - return mRenderer->clear(clearParams, mState.getDrawFramebuffer()); + return mRenderer->clear(getData(), mask); } -Error Context::clearBufferfv(GLenum buffer, int drawbuffer, const float *values) +Error Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values) { if (mState.isRasterizerDiscardEnabled()) { return Error(GL_NO_ERROR); } - // glClearBufferfv can be called to clear the color buffer or depth buffer - ClearParameters clearParams = mState.getClearParameters(0); - - if (buffer == GL_COLOR) - { - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorFClearValue = ColorF(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_FLOAT; - } - - if (buffer == GL_DEPTH) - { - clearParams.clearDepth = true; - clearParams.depthClearValue = values[0]; - } - - applyRenderTarget(GL_TRIANGLES, true); // Clips the clear to the scissor rectangle but not the viewport - - return mRenderer->clear(clearParams, mState.getDrawFramebuffer()); + return mRenderer->clearBufferfv(getData(), buffer, drawbuffer, values); } -Error Context::clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values) +Error Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values) { if (mState.isRasterizerDiscardEnabled()) { return Error(GL_NO_ERROR); } - // glClearBufferuv can only be called to clear a color buffer - ClearParameters clearParams = mState.getClearParameters(0); - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorUIClearValue = ColorUI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_UNSIGNED_INT; - - applyRenderTarget(GL_TRIANGLES, true); // Clips the clear to the scissor rectangle but not the viewport - - return mRenderer->clear(clearParams, mState.getDrawFramebuffer()); + return mRenderer->clearBufferuiv(getData(), buffer, drawbuffer, values); } -Error Context::clearBufferiv(GLenum buffer, int drawbuffer, const int *values) +Error Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values) { if (mState.isRasterizerDiscardEnabled()) { return Error(GL_NO_ERROR); } - // glClearBufferfv can be called to clear the color buffer or stencil buffer - ClearParameters clearParams = mState.getClearParameters(0); - - if (buffer == GL_COLOR) - { - for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) - { - clearParams.clearColor[i] = (drawbuffer == static_cast(i)); - } - clearParams.colorIClearValue = ColorI(values[0], values[1], values[2], values[3]); - clearParams.colorClearType = GL_INT; - } - - if (buffer == GL_STENCIL) - { - clearParams.clearStencil = true; - clearParams.stencilClearValue = values[1]; - } - - applyRenderTarget(GL_TRIANGLES, true); // Clips the clear to the scissor rectangle but not the viewport - - return mRenderer->clear(clearParams, mState.getDrawFramebuffer()); + return mRenderer->clearBufferiv(getData(), buffer, drawbuffer, values); } -Error Context::clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil) +Error Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { if (mState.isRasterizerDiscardEnabled()) { return Error(GL_NO_ERROR); } - // glClearBufferfi can only be called to clear a depth stencil buffer - ClearParameters clearParams = mState.getClearParameters(0); - clearParams.clearDepth = true; - clearParams.depthClearValue = depth; - clearParams.clearStencil = true; - clearParams.stencilClearValue = stencil; - - applyRenderTarget(GL_TRIANGLES, true); // Clips the clear to the scissor rectangle but not the viewport - - return mRenderer->clear(clearParams, mState.getDrawFramebuffer()); + return mRenderer->clearBufferfi(getData(), buffer, drawbuffer, depth, stencil); } Error Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels) { - Framebuffer *framebuffer = mState.getReadFramebuffer(); - - GLenum sizedInternalFormat = GetSizedInternalFormat(format, type); - const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat); - GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, width, mState.getPackAlignment()); - - return mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, mState.getPackState(), - reinterpret_cast(pixels)); + return mRenderer->readPixels(getData(), x, y, width, height, format, type, bufSize, pixels); } Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances) { - ASSERT(mState.getCurrentProgramId() != 0); - - ProgramBinary *programBinary = mState.getCurrentProgramBinary(); - programBinary->updateSamplerMapping(); - - Error error = generateSwizzles(programBinary); - if (error.isError()) - { - return error; - } - - if (!mRenderer->applyPrimitiveType(mode, count)) - { - return Error(GL_NO_ERROR); - } - - error = applyRenderTarget(mode, false); - if (error.isError()) - { - return error; - } - - error = applyState(mode); - if (error.isError()) - { - return error; - } - - error = mRenderer->applyVertexBuffer(programBinary, mState.getVertexArray()->getVertexAttributes(), mState.getVertexAttribCurrentValues(), first, count, instances); - if (error.isError()) - { - return error; - } - - bool transformFeedbackActive = applyTransformFeedbackBuffers(); - - error = applyShaders(programBinary, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - error = applyTextures(programBinary); - if (error.isError()) - { - return error; - } - - error = applyUniformBuffers(); - if (error.isError()) - { - return error; - } - - if (!skipDraw(mode)) - { - error = mRenderer->drawArrays(mode, count, instances, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - if (transformFeedbackActive) - { - markTransformFeedbackUsage(); - } - } - - return gl::Error(GL_NO_ERROR); + return mRenderer->drawArrays(getData(), mode, first, count, instances); } Error Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances, const rx::RangeUI &indexRange) { - ASSERT(mState.getCurrentProgramId() != 0); - - ProgramBinary *programBinary = mState.getCurrentProgramBinary(); - programBinary->updateSamplerMapping(); - - Error error = generateSwizzles(programBinary); - if (error.isError()) - { - return error; - } - - if (!mRenderer->applyPrimitiveType(mode, count)) - { - return Error(GL_NO_ERROR); - } - - error = applyRenderTarget(mode, false); - if (error.isError()) - { - return error; - } - - error = applyState(mode); - if (error.isError()) - { - return error; - } - - VertexArray *vao = mState.getVertexArray(); - rx::TranslatedIndexData indexInfo; - indexInfo.indexRange = indexRange; - error = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); - if (error.isError()) - { - return error; - } - - GLsizei vertexCount = indexInfo.indexRange.length() + 1; - error = mRenderer->applyVertexBuffer(programBinary, vao->getVertexAttributes(), - mState.getVertexAttribCurrentValues(), - indexInfo.indexRange.start, vertexCount, instances); - if (error.isError()) - { - return error; - } - - bool transformFeedbackActive = applyTransformFeedbackBuffers(); - // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation - // layer. - ASSERT(!transformFeedbackActive); - - error = applyShaders(programBinary, transformFeedbackActive); - if (error.isError()) - { - return error; - } - - error = applyTextures(programBinary); - if (error.isError()) - { - return error; - } - - error = applyUniformBuffers(); - if (error.isError()) - { - return error; - } - - if (!skipDraw(mode)) - { - error = mRenderer->drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); - if (error.isError()) - { - return error; - } - } - - return Error(GL_NO_ERROR); + return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange); } // Implements glFlush when block is false, glFinish when block is true -void Context::sync(bool block) +Error Context::sync(bool block) { - mRenderer->sync(block); + return mRenderer->sync(block); } void Context::recordError(const Error &error) @@ -1931,6 +1392,7 @@ GLenum Context::getError() GLenum Context::getResetStatus() { + //TODO(jmadill): needs MANGLE reworking if (mResetStatus == GL_NO_ERROR && !mContextLost) { // mResetStatus will be set by the markContextLost callback @@ -1981,7 +1443,7 @@ const Extensions &Context::getExtensions() const void Context::getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type) { Framebuffer *framebuffer = mState.getReadFramebuffer(); - ASSERT(framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE); + ASSERT(framebuffer && framebuffer->completeness(getData()) == GL_FRAMEBUFFER_COMPLETE); FramebufferAttachment *attachment = framebuffer->getReadColorbuffer(); ASSERT(attachment); @@ -2000,7 +1462,7 @@ void Context::detachTexture(GLuint texture) // allocation map management either here or in the resource manager at detach time. // Zero textures are held by the Context, and we don't attempt to request them from // the State. - mState.detachTexture(texture); + mState.detachTexture(mZeroTextures, texture); } void Context::detachBuffer(GLuint buffer) @@ -2072,95 +1534,6 @@ void Context::detachSampler(GLuint sampler) mState.detachSampler(sampler); } -Texture *Context::getIncompleteTexture(GLenum type) -{ - if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) - { - const GLubyte color[] = { 0, 0, 0, 255 }; - const PixelUnpackState incompleteUnpackState(1); - - Texture* t = NULL; - switch (type) - { - default: - UNREACHABLE(); - // default falls through to TEXTURE_2D - - case GL_TEXTURE_2D: - { - Texture2D *incomplete2d = new Texture2D(mRenderer->createTexture(GL_TEXTURE_2D), Texture::INCOMPLETE_TEXTURE_ID); - incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - t = incomplete2d; - } - break; - - case GL_TEXTURE_CUBE_MAP: - { - TextureCubeMap *incompleteCube = new TextureCubeMap(mRenderer->createTexture(GL_TEXTURE_CUBE_MAP), Texture::INCOMPLETE_TEXTURE_ID); - - incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incompleteCube; - } - break; - - case GL_TEXTURE_3D: - { - Texture3D *incomplete3d = new Texture3D(mRenderer->createTexture(GL_TEXTURE_3D), Texture::INCOMPLETE_TEXTURE_ID); - incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incomplete3d; - } - break; - - case GL_TEXTURE_2D_ARRAY: - { - Texture2DArray *incomplete2darray = new Texture2DArray(mRenderer->createTexture(GL_TEXTURE_2D_ARRAY), Texture::INCOMPLETE_TEXTURE_ID); - incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); - - t = incomplete2darray; - } - break; - } - - mIncompleteTextures[type].set(t); - } - - return mIncompleteTextures[type].get(); -} - -bool Context::skipDraw(GLenum drawMode) -{ - if (drawMode == GL_POINTS) - { - // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, - // which affects varying interpolation. Since the value of gl_PointSize is - // undefined when not written, just skip drawing to avoid unexpected results. - if (!mState.getCurrentProgramBinary()->usesPointSize()) - { - // This is stictly speaking not an error, but developers should be - // notified of risking undefined behavior. - ERR("Point rendering without writing to gl_PointSize."); - - return true; - } - } - else if (IsTriangleMode(drawMode)) - { - if (mState.getRasterizerState().cullFace && mState.getRasterizerState().cullMode == GL_FRONT_AND_BACK) - { - return true; - } - } - - return false; -} - void Context::setVertexAttribDivisor(GLuint index, GLuint divisor) { mState.getVertexArray()->setVertexAttribDivisor(index, divisor); @@ -2293,63 +1666,12 @@ size_t Context::getExtensionStringCount() const return mExtensionStrings.size(); } -size_t Context::getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray) +Error Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) { - size_t serialCount = 0; - - Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); - for (unsigned int i = 0; i < IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) - { - FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); - if (attachment && attachment->isTexture()) - { - Texture *texture = attachment->getTexture(); - (*outSerialArray)[serialCount++] = texture->getTextureSerial(); - } - } - - FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); - if (depthStencilAttachment && depthStencilAttachment->isTexture()) - { - Texture *depthStencilTexture = depthStencilAttachment->getTexture(); - (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial(); - } - - std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); - - return serialCount; -} - -void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) -{ - Framebuffer *readFramebuffer = mState.getReadFramebuffer(); - Framebuffer *drawFramebuffer = mState.getDrawFramebuffer(); - - bool blitRenderTarget = false; - bool blitDepth = false; - bool blitStencil = false; - if ((mask & GL_COLOR_BUFFER_BIT) && readFramebuffer->getReadColorbuffer() && drawFramebuffer->getFirstColorbuffer()) - { - blitRenderTarget = true; - } - if ((mask & GL_STENCIL_BUFFER_BIT) && readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) - { - blitStencil = true; - } - if ((mask & GL_DEPTH_BUFFER_BIT) && readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) - { - blitDepth = true; - } - - Rectangle srcRect(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); - Rectangle dstRect(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); - if (blitRenderTarget || blitDepth || blitStencil) - { - const Rectangle *scissor = mState.isScissorTestEnabled() ? &mState.getScissor() : NULL; - mRenderer->blitRect(readFramebuffer, srcRect, drawFramebuffer, dstRect, scissor, - blitRenderTarget, blitDepth, blitStencil, filter); - } + return mRenderer->blitFramebuffer(getData(), srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, mask, filter); } void Context::releaseShaderCompiler() @@ -2416,6 +1738,11 @@ void Context::initCaps(GLuint clientVersion) mExtensions.maxSamples = maxSamples; } +Data Context::getData() const +{ + return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager); +} + } extern "C" diff --git a/src/3rdparty/angle/src/libGLESv2/Context.h b/src/3rdparty/angle/src/libGLESv2/Context.h index 1b888aec83..1e890de3ef 100644 --- a/src/3rdparty/angle/src/libGLESv2/Context.h +++ b/src/3rdparty/angle/src/libGLESv2/Context.h @@ -13,12 +13,12 @@ #include "common/angleutils.h" #include "common/RefCountObject.h" #include "libGLESv2/Caps.h" +#include "libGLESv2/Constants.h" +#include "libGLESv2/Data.h" #include "libGLESv2/Error.h" #include "libGLESv2/HandleAllocator.h" -#include "libGLESv2/angletypes.h" -#include "libGLESv2/Constants.h" #include "libGLESv2/VertexAttribute.h" -#include "libGLESv2/State.h" +#include "libGLESv2/angletypes.h" #include "angle_gl.h" @@ -50,11 +50,6 @@ class Texture3D; class Texture2DArray; class Framebuffer; class Renderbuffer; -class RenderbufferStorage; -class Colorbuffer; -class Depthbuffer; -class Stencilbuffer; -class DepthStencilbuffer; class FenceNV; class FenceSync; class Query; @@ -68,7 +63,7 @@ class TransformFeedback; class Context { public: - Context(int clientVersion, const gl::Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); + Context(int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess); virtual ~Context(); @@ -86,7 +81,7 @@ class Context GLuint createRenderbuffer(); GLuint createSampler(); GLuint createTransformFeedback(); - GLsync createFenceSync(GLenum condition); + GLsync createFenceSync(); void deleteBuffer(GLuint buffer); void deleteShader(GLuint shader); @@ -115,7 +110,7 @@ class Context void bindArrayBuffer(GLuint buffer); void bindElementArrayBuffer(GLuint buffer); - void bindTexture(GLenum target, GLuint texture); + void bindTexture(GLenum target, GLuint handle); void bindReadFramebuffer(GLuint framebuffer); void bindDrawFramebuffer(GLuint framebuffer); void bindRenderbuffer(GLuint renderbuffer); @@ -130,8 +125,8 @@ class Context void bindPixelPackBuffer(GLuint buffer); void bindPixelUnpackBuffer(GLuint buffer); void useProgram(GLuint program); - void linkProgram(GLuint program); - void setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length); + Error linkProgram(GLuint program); + Error setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length); void bindTransformFeedback(GLuint transformFeedback); Error beginQuery(GLenum target, GLuint query); @@ -139,8 +134,6 @@ class Context void setFramebufferZero(Framebuffer *framebuffer); - void setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples); - void setVertexAttribDivisor(GLuint index, GLuint divisor); void samplerParameteri(GLuint sampler, GLenum pname, GLint param); @@ -183,17 +176,17 @@ class Context bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams); Error clear(GLbitfield mask); - Error clearBufferfv(GLenum buffer, int drawbuffer, const float *values); - Error clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values); - Error clearBufferiv(GLenum buffer, int drawbuffer, const int *values); - Error clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil); + Error clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values); + Error clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values); + Error clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values); + Error clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); Error readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels); Error drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances); Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances, const rx::RangeUI &indexRange); - void sync(bool block); // flush/finish + Error sync(bool block); // flush/finish void recordError(const Error &error); @@ -215,32 +208,21 @@ class Context void getCurrentReadFormatType(GLenum *internalFormat, GLenum *format, GLenum *type); - void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter); + Error blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); rx::Renderer *getRenderer() { return mRenderer; } State &getState() { return mState; } const State &getState() const { return mState; } + Data getData() const; + void releaseShaderCompiler(); private: DISALLOW_COPY_AND_ASSIGN(Context); - // TODO: std::array may become unavailable using older versions of GCC - typedef std::array FramebufferTextureSerialArray; - - Error applyRenderTarget(GLenum drawMode, bool ignoreViewport); - Error applyState(GLenum drawMode); - Error applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive); - Error applyTextures(ProgramBinary *programBinary, SamplerType shaderType, const FramebufferTextureSerialArray &framebufferSerials, - size_t framebufferSerialCount); - Error applyTextures(ProgramBinary *programBinary); - Error applyUniformBuffers(); - bool applyTransformFeedbackBuffers(); - void markTransformFeedbackUsage(); - void detachBuffer(GLuint buffer); void detachTexture(GLuint texture); void detachFramebuffer(GLuint framebuffer); @@ -249,18 +231,9 @@ class Context void detachTransformFeedback(GLuint transformFeedback); void detachSampler(GLuint sampler); - Error generateSwizzles(ProgramBinary *programBinary, SamplerType type); - Error generateSwizzles(ProgramBinary *programBinary); - - Texture *getIncompleteTexture(GLenum type); - - bool skipDraw(GLenum drawMode); - void initRendererString(); void initExtensionStrings(); - size_t getBoundFramebufferTextureSerials(FramebufferTextureSerialArray *outSerialArray); - void initCaps(GLuint clientVersion); // Caps to use for validation @@ -273,7 +246,6 @@ class Context int mClientVersion; - typedef std::map< GLenum, BindingPointer > TextureMap; TextureMap mZeroTextures; TextureMap mIncompleteTextures; diff --git a/src/3rdparty/angle/src/libGLESv2/Data.cpp b/src/3rdparty/angle/src/libGLESv2/Data.cpp new file mode 100644 index 0000000000..3ddf591d77 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Data.cpp @@ -0,0 +1,51 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Data.cpp: Container class for all GL relevant state, caps and objects + +#include "libGLESv2/Data.h" +#include "libGLESv2/ResourceManager.h" + +namespace gl +{ + +Data::Data(GLint clientVersionIn, const State &stateIn, const Caps &capsIn, + const TextureCapsMap &textureCapsIn, const Extensions &extensionsIn, + const ResourceManager *resourceManagerIn) + : clientVersion(clientVersionIn), + state(&stateIn), + caps(&capsIn), + textureCaps(&textureCapsIn), + extensions(&extensionsIn), + resourceManager(resourceManagerIn) +{} + +Data::~Data() +{ +} + +Data::Data(const Data &other) + : clientVersion(other.clientVersion), + state(other.state), + caps(other.caps), + textureCaps(other.textureCaps), + extensions(other.extensions), + resourceManager(other.resourceManager) +{ +} + +Data &Data::operator=(const Data &other) +{ + clientVersion = other.clientVersion; + state = other.state; + caps = other.caps; + textureCaps = other.textureCaps; + extensions = other.extensions; + resourceManager = other.resourceManager; + return *this; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/Data.h b/src/3rdparty/angle/src/libGLESv2/Data.h new file mode 100644 index 0000000000..9234403e13 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/Data.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// Data.h: Container class for all GL relevant state, caps and objects + +#ifndef LIBGLESV2_DATA_H_ +#define LIBGLESV2_DATA_H_ + +#include "libGLESv2/State.h" + +namespace gl +{ + +struct Data +{ + public: + Data(GLint clientVersion, const State &state, const Caps &caps, + const TextureCapsMap &textureCaps, const Extensions &extensions, + const ResourceManager *resourceManager); + ~Data(); + + Data(const Data &other); + Data &operator=(const Data &other); + + GLint clientVersion; + const State *state; + const Caps *caps; + const TextureCapsMap *textureCaps; + const Extensions *extensions; + const ResourceManager *resourceManager; +}; + +} + +#endif // LIBGLESV2_DATA_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.cpp b/src/3rdparty/angle/src/libGLESv2/Fence.cpp index ee9a07a5c4..966a327de5 100644 --- a/src/3rdparty/angle/src/libGLESv2/Fence.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Fence.cpp @@ -4,191 +4,113 @@ // found in the LICENSE file. // -// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension. - -// Important note on accurate timers in Windows: -// -// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call -// as timeGetTime on laptops and "jumping" during certain hardware events. -// -// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" -// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc -// -// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer -// from buggy implementations. +// Fence.cpp: Implements the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. #include "libGLESv2/Fence.h" #include "libGLESv2/renderer/FenceImpl.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/main.h" +#include "common/utilities.h" #include "angle_gl.h" namespace gl { -FenceNV::FenceNV(rx::Renderer *renderer) +FenceNV::FenceNV(rx::FenceNVImpl *impl) + : mFence(impl), + mIsSet(false), + mStatus(GL_FALSE), + mCondition(GL_NONE) { - mFence = renderer->createFence(); } FenceNV::~FenceNV() { - delete mFence; + SafeDelete(mFence); } GLboolean FenceNV::isFence() const { // GL_NV_fence spec: // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence. - return (mFence->isSet() ? GL_TRUE : GL_FALSE); + return (mIsSet ? GL_TRUE : GL_FALSE); } -void FenceNV::setFence(GLenum condition) +Error FenceNV::setFence(GLenum condition) { - mFence->set(); + Error error = mFence->set(); + if (error.isError()) + { + return error; + } mCondition = condition; mStatus = GL_FALSE; + mIsSet = true; + + return Error(GL_NO_ERROR); } -GLboolean FenceNV::testFence() +Error FenceNV::testFence(GLboolean *outResult) { // Flush the command buffer by default - bool result = mFence->test(true); - - mStatus = (result ? GL_TRUE : GL_FALSE); - return mStatus; -} - -void FenceNV::finishFence() -{ - ASSERT(mFence->isSet()); - - while (!mFence->test(true)) + Error error = mFence->test(true, &mStatus); + if (error.isError()) { - Sleep(0); + return error; } + + *outResult = mStatus; + return Error(GL_NO_ERROR); } -GLint FenceNV::getFencei(GLenum pname) +Error FenceNV::finishFence() { - ASSERT(mFence->isSet()); + ASSERT(mIsSet); - switch (pname) - { - case GL_FENCE_STATUS_NV: - { - // GL_NV_fence spec: - // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV - // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. - if (mStatus == GL_TRUE) - { - return GL_TRUE; - } - - mStatus = (mFence->test(false) ? GL_TRUE : GL_FALSE); - return mStatus; - } - - case GL_FENCE_CONDITION_NV: - return mCondition; - - default: UNREACHABLE(); return 0; - } + return mFence->finishFence(&mStatus); } -FenceSync::FenceSync(rx::Renderer *renderer, GLuint id) - : RefCountObject(id) +FenceSync::FenceSync(rx::FenceSyncImpl *impl, GLuint id) + : RefCountObject(id), + mFence(impl), + mCondition(GL_NONE) { - mFence = renderer->createFence(); - - LARGE_INTEGER counterFreqency = { 0 }; - BOOL success = QueryPerformanceFrequency(&counterFreqency); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - - mCounterFrequency = counterFreqency.QuadPart; } FenceSync::~FenceSync() { - delete mFence; + SafeDelete(mFence); } -void FenceSync::set(GLenum condition) +Error FenceSync::set(GLenum condition) { + Error error = mFence->set(); + if (error.isError()) + { + return error; + } + mCondition = condition; - mFence->set(); + return Error(GL_NO_ERROR); } -GLenum FenceSync::clientWait(GLbitfield flags, GLuint64 timeout) +Error FenceSync::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) { - ASSERT(mFence->isSet()); - - bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); - - if (mFence->test(flushCommandBuffer)) - { - return GL_ALREADY_SIGNALED; - } - - if (mFence->hasError()) - { - return GL_WAIT_FAILED; - } - - if (timeout == 0) - { - return GL_TIMEOUT_EXPIRED; - } - - LARGE_INTEGER currentCounter = { 0 }; - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - - LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); - LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; - - while (currentCounter.QuadPart < endCounter && !mFence->test(flushCommandBuffer)) - { - Sleep(0); - BOOL success = QueryPerformanceCounter(¤tCounter); - UNUSED_ASSERTION_VARIABLE(success); - ASSERT(success); - } - - if (mFence->hasError()) - { - return GL_WAIT_FAILED; - } - - if (currentCounter.QuadPart >= endCounter) - { - return GL_TIMEOUT_EXPIRED; - } - - return GL_CONDITION_SATISFIED; + ASSERT(mCondition != GL_NONE); + return mFence->clientWait(flags, timeout, outResult); } -void FenceSync::serverWait() +Error FenceSync::serverWait(GLbitfield flags, GLuint64 timeout) { - // Because our API is currently designed to be called from a single thread, we don't need to do - // extra work for a server-side fence. GPU commands issued after the fence is created will always - // be processed after the fence is signaled. + return mFence->serverWait(flags, timeout); } -GLenum FenceSync::getStatus() const +Error FenceSync::getStatus(GLint *outResult) const { - if (mFence->test(false)) - { - // The spec does not specify any way to report errors during the status test (e.g. device lost) - // so we report the fence is unblocked in case of error or signaled. - return GL_SIGNALED; - } - - return GL_UNSIGNALED; + return mFence->getStatus(outResult); } } diff --git a/src/3rdparty/angle/src/libGLESv2/Fence.h b/src/3rdparty/angle/src/libGLESv2/Fence.h index 291edb3de1..fd565e96a6 100644 --- a/src/3rdparty/angle/src/libGLESv2/Fence.h +++ b/src/3rdparty/angle/src/libGLESv2/Fence.h @@ -4,18 +4,21 @@ // found in the LICENSE file. // -// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension. +// Fence.h: Defines the gl::FenceNV and gl::FenceSync classes, which support the GL_NV_fence +// extension and GLES3 sync objects. #ifndef LIBGLESV2_FENCE_H_ #define LIBGLESV2_FENCE_H_ +#include "libGLESv2/Error.h" + #include "common/angleutils.h" #include "common/RefCountObject.h" namespace rx { -class Renderer; -class FenceImpl; +class FenceNVImpl; +class FenceSyncImpl; } namespace gl @@ -24,14 +27,13 @@ namespace gl class FenceNV { public: - explicit FenceNV(rx::Renderer *renderer); + explicit FenceNV(rx::FenceNVImpl *impl); virtual ~FenceNV(); GLboolean isFence() const; - void setFence(GLenum condition); - GLboolean testFence(); - void finishFence(); - GLint getFencei(GLenum pname); + Error setFence(GLenum condition); + Error testFence(GLboolean *outResult); + Error finishFence(); GLboolean getStatus() const { return mStatus; } GLuint getCondition() const { return mCondition; } @@ -39,7 +41,9 @@ class FenceNV private: DISALLOW_COPY_AND_ASSIGN(FenceNV); - rx::FenceImpl *mFence; + rx::FenceNVImpl *mFence; + + bool mIsSet; GLboolean mStatus; GLenum mCondition; @@ -48,21 +52,20 @@ class FenceNV class FenceSync : public RefCountObject { public: - explicit FenceSync(rx::Renderer *renderer, GLuint id); + explicit FenceSync(rx::FenceSyncImpl *impl, GLuint id); virtual ~FenceSync(); - void set(GLenum condition); - GLenum clientWait(GLbitfield flags, GLuint64 timeout); - void serverWait(); - GLenum getStatus() const; + Error set(GLenum condition); + Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + Error serverWait(GLbitfield flags, GLuint64 timeout); + Error getStatus(GLint *outResult) const; GLuint getCondition() const { return mCondition; } private: DISALLOW_COPY_AND_ASSIGN(FenceSync); - rx::FenceImpl *mFence; - LONGLONG mCounterFrequency; + rx::FenceSyncImpl *mFence; GLenum mCondition; }; diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp index 5b21433f90..3d57262e3c 100644 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.cpp @@ -16,13 +16,18 @@ #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/renderer/RenderbufferImpl.h" +#include "libGLESv2/renderer/Workarounds.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" #include "common/utilities.h" namespace rx { -RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) +// TODO: Move these functions, and the D3D-specific header inclusions above, +// to FramebufferD3D. +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT) { if (attachment->isTexture()) { @@ -31,14 +36,16 @@ RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); const gl::ImageIndex *index = attachment->getTextureImageIndex(); ASSERT(index); - return textureD3D->getRenderTarget(*index); + return textureD3D->getRenderTarget(*index, outRT); + } + else + { + gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); + ASSERT(renderbuffer); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + *outRT = renderbufferD3D->getRenderTarget(); + return gl::Error(GL_NO_ERROR); } - - gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); - ASSERT(renderbuffer); - - // TODO: cast to RenderbufferD3D - return renderbuffer->getStorage()->getRenderTarget(); } // Note: RenderTarget serials should ideally be in the RenderTargets themselves. @@ -56,9 +63,8 @@ unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment) gl::Renderbuffer *renderbuffer = attachment->getRenderbuffer(); ASSERT(renderbuffer); - - // TODO: cast to RenderbufferD3D - return renderbuffer->getStorage()->getSerial(); + RenderbufferD3D *renderbufferD3D = RenderbufferD3D::makeRenderbufferD3D(renderbuffer->getImplementation()); + return renderbufferD3D->getRenderTargetSerial(); } } @@ -66,9 +72,8 @@ unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment) namespace gl { -Framebuffer::Framebuffer(rx::Renderer *renderer, GLuint id) - : mRenderer(renderer), - mId(id), +Framebuffer::Framebuffer(GLuint id) + : mId(id), mReadBufferState(GL_COLOR_ATTACHMENT0_EXT), mDepthbuffer(NULL), mStencilbuffer(NULL) @@ -91,124 +96,6 @@ Framebuffer::~Framebuffer() SafeDelete(mStencilbuffer); } -FramebufferAttachment *Framebuffer::createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const -{ - if (handle == 0) - { - return NULL; - } - - gl::Context *context = gl::getContext(); - - switch (type) - { - case GL_NONE: - return NULL; - - case GL_RENDERBUFFER: - return new RenderbufferAttachment(binding, context->getRenderbuffer(handle)); - - case GL_TEXTURE_2D: - { - Texture *texture = context->getTexture(handle); - if (texture && texture->getTarget() == GL_TEXTURE_2D) - { - return new TextureAttachment(binding, texture, ImageIndex::Make2D(level)); - } - else - { - return NULL; - } - } - - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - { - Texture *texture = context->getTexture(handle); - if (texture && texture->getTarget() == GL_TEXTURE_CUBE_MAP) - { - return new TextureAttachment(binding, texture, ImageIndex::MakeCube(type, level)); - } - else - { - return NULL; - } - } - - case GL_TEXTURE_3D: - { - Texture *texture = context->getTexture(handle); - if (texture && texture->getTarget() == GL_TEXTURE_3D) - { - return new TextureAttachment(binding, texture, ImageIndex::Make3D(level, layer)); - } - else - { - return NULL; - } - } - - case GL_TEXTURE_2D_ARRAY: - { - Texture *texture = context->getTexture(handle); - if (texture && texture->getTarget() == GL_TEXTURE_2D_ARRAY) - { - return new TextureAttachment(binding, texture, ImageIndex::Make2DArray(level, layer)); - } - else - { - return NULL; - } - } - - default: - UNREACHABLE(); - return NULL; - } -} - -void Framebuffer::setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer) -{ - ASSERT(colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS); - SafeDelete(mColorbuffers[colorAttachment]); - GLenum binding = colorAttachment + GL_COLOR_ATTACHMENT0; - mColorbuffers[colorAttachment] = createAttachment(binding, type, colorbuffer, level, layer); -} - -void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer) -{ - SafeDelete(mDepthbuffer); - mDepthbuffer = createAttachment(GL_DEPTH_ATTACHMENT, type, depthbuffer, level, layer); -} - -void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer) -{ - SafeDelete(mStencilbuffer); - mStencilbuffer = createAttachment(GL_STENCIL_ATTACHMENT, type, stencilbuffer, level, layer); -} - -void Framebuffer::setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer) -{ - FramebufferAttachment *attachment = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer); - - SafeDelete(mDepthbuffer); - SafeDelete(mStencilbuffer); - - // ensure this is a legitimate depth+stencil format - if (attachment && attachment->getDepthSize() > 0 && attachment->getStencilSize() > 0) - { - mDepthbuffer = attachment; - - // Make a new attachment object to ensure we do not double-delete - // See angle issue 686 - mStencilbuffer = createAttachment(GL_DEPTH_STENCIL_ATTACHMENT, type, depthStencilBuffer, level, layer); - } -} - void Framebuffer::detachTexture(GLuint textureId) { for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) @@ -382,14 +269,13 @@ bool Framebuffer::usingExtendedDrawBuffers() const return false; } -GLenum Framebuffer::completeness() const +GLenum Framebuffer::completeness(const gl::Data &data) const { int width = 0; int height = 0; unsigned int colorbufferSize = 0; int samples = -1; bool missingAttachment = true; - GLuint clientVersion = mRenderer->getCurrentClientVersion(); for (unsigned int colorAttachment = 0; colorAttachment < IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { @@ -403,8 +289,7 @@ GLenum Framebuffer::completeness() const } GLenum internalformat = colorbuffer->getInternalFormat(); - // TODO(geofflang): use context's texture caps - const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); if (colorbuffer->isTexture()) { @@ -443,7 +328,7 @@ GLenum Framebuffer::completeness() const // in GLES 2.0, all color attachments attachments must have the same number of bitplanes // in GLES 3.0, there is no such restriction - if (clientVersion < 3) + if (data.clientVersion < 3) { if (formatInfo.pixelBytes != colorbufferSize) { @@ -483,14 +368,12 @@ GLenum Framebuffer::completeness() const } GLenum internalformat = mDepthbuffer->getInternalFormat(); - // TODO(geofflang): use context's texture caps - const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); if (mDepthbuffer->isTexture()) { // depth texture attachments require OES/ANGLE_depth_texture - // TODO(geofflang): use context's extensions - if (!mRenderer->getRendererExtensions().depthTextures) + if (!data.extensions->depthTextures) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } @@ -538,15 +421,13 @@ GLenum Framebuffer::completeness() const } GLenum internalformat = mStencilbuffer->getInternalFormat(); - // TODO(geofflang): use context's texture caps - const TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(internalformat); + const TextureCaps &formatCaps = data.textureCaps->get(internalformat); const InternalFormat &formatInfo = GetInternalFormatInfo(internalformat); if (mStencilbuffer->isTexture()) { // texture stencil attachments come along as part // of OES_packed_depth_stencil + OES/ANGLE_depth_texture - // TODO(geofflang): use context's extensions - if (!mRenderer->getRendererExtensions().depthTextures) + if (!data.extensions->depthTextures) { return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; } @@ -602,42 +483,44 @@ GLenum Framebuffer::completeness() const return GL_FRAMEBUFFER_COMPLETE; } -void Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments) +Error Framebuffer::invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments) { GLuint maxDimension = caps.maxRenderbufferSize; - invalidateSub(caps, numAttachments, attachments, 0, 0, maxDimension, maxDimension); + return invalidateSub(numAttachments, attachments, 0, 0, maxDimension, maxDimension); } -void Framebuffer::invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments, - GLint x, GLint y, GLsizei width, GLsizei height) +Error Framebuffer::invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) { - ASSERT(completeness() == GL_FRAMEBUFFER_COMPLETE); for (GLsizei attachIndex = 0; attachIndex < numAttachments; ++attachIndex) { GLenum attachmentTarget = attachments[attachIndex]; - gl::FramebufferAttachment *attachment = - (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() : - getAttachment(attachmentTarget); + FramebufferAttachment *attachment = (attachmentTarget == GL_DEPTH_STENCIL_ATTACHMENT) ? getDepthOrStencilbuffer() + : getAttachment(attachmentTarget); if (attachment) { - rx::RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); - if (renderTarget) + rx::RenderTarget *renderTarget = NULL; + Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) { - renderTarget->invalidate(x, y, width, height); + return error; } + + renderTarget->invalidate(x, y, width, height); } } + + return Error(GL_NO_ERROR); } -DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil) - : Framebuffer(renderer, 0) +DefaultFramebuffer::DefaultFramebuffer(rx::RenderbufferImpl *colorbuffer, rx::RenderbufferImpl *depthStencil) + : Framebuffer(0) { - Renderbuffer *colorRenderbuffer = new Renderbuffer(0, colorbuffer); + Renderbuffer *colorRenderbuffer = new Renderbuffer(colorbuffer, 0); mColorbuffers[0] = new RenderbufferAttachment(GL_BACK, colorRenderbuffer); - Renderbuffer *depthStencilBuffer = new Renderbuffer(0, depthStencil); + Renderbuffer *depthStencilBuffer = new Renderbuffer(depthStencil, 0); // Make a new attachment objects to ensure we do not double-delete // See angle issue 686 @@ -648,9 +531,9 @@ DefaultFramebuffer::DefaultFramebuffer(rx::Renderer *renderer, Colorbuffer *colo mReadBufferState = GL_BACK; } -int Framebuffer::getSamples() const +int Framebuffer::getSamples(const gl::Data &data) const { - if (completeness() == GL_FRAMEBUFFER_COMPLETE) + if (completeness(data) == GL_FRAMEBUFFER_COMPLETE) { // for a complete framebuffer, all attachments must have the same sample count // in this case return the first nonzero sample size @@ -675,7 +558,7 @@ bool Framebuffer::hasValidDepthStencil() const mDepthbuffer->id() == mStencilbuffer->id()); } -ColorbufferInfo Framebuffer::getColorbuffersForRender() const +ColorbufferInfo Framebuffer::getColorbuffersForRender(const rx::Workarounds &workarounds) const { ColorbufferInfo colorbuffersForRender; @@ -689,18 +572,78 @@ ColorbufferInfo Framebuffer::getColorbuffersForRender() const ASSERT(drawBufferState == GL_BACK || drawBufferState == (GL_COLOR_ATTACHMENT0_EXT + colorAttachment)); colorbuffersForRender.push_back(colorbuffer); } -#if (ANGLE_MRT_PERF_WORKAROUND == ANGLE_WORKAROUND_DISABLED) - else + else if (!workarounds.mrtPerfWorkaround) { colorbuffersForRender.push_back(NULL); } -#endif } return colorbuffersForRender; } -GLenum DefaultFramebuffer::completeness() const +void Framebuffer::setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex) +{ + setAttachment(attachment, new TextureAttachment(attachment, texture, imageIndex)); +} + +void Framebuffer::setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer) +{ + setAttachment(attachment, new RenderbufferAttachment(attachment, renderbuffer)); +} + +void Framebuffer::setNULLAttachment(GLenum attachment) +{ + setAttachment(attachment, NULL); +} + +void Framebuffer::setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj) +{ + if (attachment >= GL_COLOR_ATTACHMENT0 && attachment < (GL_COLOR_ATTACHMENT0 + IMPLEMENTATION_MAX_DRAW_BUFFERS)) + { + size_t colorAttachment = attachment - GL_COLOR_ATTACHMENT0; + SafeDelete(mColorbuffers[colorAttachment]); + mColorbuffers[colorAttachment] = attachmentObj; + } + else if (attachment == GL_DEPTH_ATTACHMENT) + { + SafeDelete(mDepthbuffer); + mDepthbuffer = attachmentObj; + } + else if (attachment == GL_STENCIL_ATTACHMENT) + { + SafeDelete(mStencilbuffer); + mStencilbuffer = attachmentObj; + } + else if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) + { + SafeDelete(mDepthbuffer); + SafeDelete(mStencilbuffer); + + // ensure this is a legitimate depth+stencil format + if (attachmentObj && attachmentObj->getDepthSize() > 0 && attachmentObj->getStencilSize() > 0) + { + mDepthbuffer = attachmentObj; + + // Make a new attachment object to ensure we do not double-delete + // See angle issue 686 + if (attachmentObj->isTexture()) + { + mStencilbuffer = new TextureAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getTexture(), + *attachmentObj->getTextureImageIndex()); + } + else + { + mStencilbuffer = new RenderbufferAttachment(GL_DEPTH_STENCIL_ATTACHMENT, attachmentObj->getRenderbuffer()); + } + } + } + else + { + UNREACHABLE(); + } +} + +GLenum DefaultFramebuffer::completeness(const gl::Data &) const { // The default framebuffer *must* always be complete, though it may not be // subject to the same rules as application FBOs. ie, it could have 0x0 size. diff --git a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h index cc12d22953..d0fe8935ea 100644 --- a/src/3rdparty/angle/src/libGLESv2/Framebuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Framebuffer.h @@ -10,41 +10,44 @@ #ifndef LIBGLESV2_FRAMEBUFFER_H_ #define LIBGLESV2_FRAMEBUFFER_H_ -#include +#include "libGLESv2/Error.h" #include "common/angleutils.h" #include "common/RefCountObject.h" -#include "constants.h" +#include "Constants.h" + +#include namespace rx { -class Renderer; +class RenderbufferImpl; +struct Workarounds; } namespace gl { class FramebufferAttachment; -class Colorbuffer; -class Depthbuffer; -class Stencilbuffer; -class DepthStencilbuffer; +class Texture; +class Renderbuffer; +struct ImageIndex; struct Caps; +struct Extensions; +class TextureCapsMap; +struct Data; typedef std::vector ColorbufferInfo; class Framebuffer { public: - Framebuffer(rx::Renderer *renderer, GLuint id); - + Framebuffer(GLuint id); virtual ~Framebuffer(); GLuint id() const { return mId; } - void setColorbuffer(unsigned int colorAttachment, GLenum type, GLuint colorbuffer, GLint level, GLint layer); - void setDepthbuffer(GLenum type, GLuint depthbuffer, GLint level, GLint layer); - void setStencilbuffer(GLenum type, GLuint stencilbuffer, GLint level, GLint layer); - void setDepthStencilBuffer(GLenum type, GLuint depthStencilBuffer, GLint level, GLint layer); + void setTextureAttachment(GLenum attachment, Texture *texture, const ImageIndex &imageIndex); + void setRenderbufferAttachment(GLenum attachment, Renderbuffer *renderbuffer); + void setNULLAttachment(GLenum attachment); void detachTexture(GLuint texture); void detachRenderbuffer(GLuint renderbuffer); @@ -66,24 +69,21 @@ class Framebuffer bool isEnabledColorAttachment(unsigned int colorAttachment) const; bool hasEnabledColorAttachment() const; bool hasStencil() const; - int getSamples() const; + int getSamples(const gl::Data &data) const; bool usingExtendedDrawBuffers() const; - virtual GLenum completeness() const; + virtual GLenum completeness(const gl::Data &data) const; bool hasValidDepthStencil() const; - void invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments); - void invalidateSub(const Caps &caps, GLsizei numAttachments, const GLenum *attachments, - GLint x, GLint y, GLsizei width, GLsizei height); + Error invalidate(const Caps &caps, GLsizei numAttachments, const GLenum *attachments); + Error invalidateSub(GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); // Use this method to retrieve the color buffer map when doing rendering. // It will apply a workaround for poor shader performance on some systems // by compacting the list to skip NULL values. - ColorbufferInfo getColorbuffersForRender() const; + ColorbufferInfo getColorbuffersForRender(const rx::Workarounds &workarounds) const; protected: - rx::Renderer *mRenderer; - GLuint mId; FramebufferAttachment *mColorbuffers[IMPLEMENTATION_MAX_DRAW_BUFFERS]; @@ -96,15 +96,15 @@ class Framebuffer private: DISALLOW_COPY_AND_ASSIGN(Framebuffer); - FramebufferAttachment *createAttachment(GLenum binding, GLenum type, GLuint handle, GLint level, GLint layer) const; + void setAttachment(GLenum attachment, FramebufferAttachment *attachmentObj); }; class DefaultFramebuffer : public Framebuffer { public: - DefaultFramebuffer(rx::Renderer *Renderer, Colorbuffer *colorbuffer, DepthStencilbuffer *depthStencil); + DefaultFramebuffer(rx::RenderbufferImpl *colorbuffer, rx::RenderbufferImpl *depthStencil); - virtual GLenum completeness() const; + GLenum completeness(const gl::Data &data) const override; virtual FramebufferAttachment *getAttachment(GLenum attachment) const; private: @@ -118,7 +118,7 @@ namespace rx class RenderTarget; // TODO: place this in FramebufferD3D.h -RenderTarget *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment); +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget **outRT); unsigned int GetAttachmentSerial(gl::FramebufferAttachment *attachment); } diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp index 540ede1cd2..894884a6d8 100644 --- a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp +++ b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.cpp @@ -187,7 +187,7 @@ GLenum RenderbufferAttachment::getActualFormat() const GLsizei RenderbufferAttachment::getSamples() const { - return mRenderbuffer->getStorage()->getSamples(); + return mRenderbuffer->getSamples(); } GLuint RenderbufferAttachment::id() const diff --git a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h index c18ef7364d..8d2dafa7ee 100644 --- a/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h +++ b/src/3rdparty/angle/src/libGLESv2/FramebufferAttachment.h @@ -16,13 +16,6 @@ #include "angle_gl.h" -namespace rx -{ -class Renderer; -class RenderTarget; -class TextureStorage; -} - namespace gl { class Renderbuffer; diff --git a/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp b/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp index 3522b997e8..b45cd9c169 100644 --- a/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ImageIndex.cpp @@ -48,10 +48,101 @@ ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex) return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex); } +ImageIndex ImageIndex::MakeInvalid() +{ + return ImageIndex(GL_NONE, -1, -1); +} + ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn) : type(typeIn), mipIndex(mipIndexIn), layerIndex(layerIndexIn) {} +ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_2D, rx::Range(minMip, maxMip), + rx::Range(ImageIndex::ENTIRE_LEVEL, ImageIndex::ENTIRE_LEVEL), NULL); +} + +ImageIndexIterator ImageIndexIterator::MakeCube(GLint minMip, GLint maxMip) +{ + return ImageIndexIterator(GL_TEXTURE_CUBE_MAP, rx::Range(minMip, maxMip), rx::Range(0, 6), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make3D(GLint minMip, GLint maxMip, + GLint minLayer, GLint maxLayer) +{ + return ImageIndexIterator(GL_TEXTURE_3D, rx::Range(minMip, maxMip), rx::Range(minLayer, maxLayer), NULL); +} + +ImageIndexIterator ImageIndexIterator::Make2DArray(GLint minMip, GLint maxMip, + const GLsizei *layerCounts) +{ + return ImageIndexIterator(GL_TEXTURE_2D_ARRAY, rx::Range(minMip, maxMip), + rx::Range(0, IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS), layerCounts); +} + +ImageIndexIterator::ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts) + : mType(type), + mMipRange(mipRange), + mLayerRange(layerRange), + mLayerCounts(layerCounts), + mCurrentMip(mipRange.start), + mCurrentLayer(layerRange.start) +{} + +GLint ImageIndexIterator::maxLayer() const +{ + return (mLayerCounts ? static_cast(mLayerCounts[mCurrentMip]) : mLayerRange.end); +} + +ImageIndex ImageIndexIterator::next() +{ + ASSERT(hasNext()); + + ImageIndex value = current(); + + // Iterate layers in the inner loop for now. We can add switchable + // layer or mip iteration if we need it. + + if (mCurrentLayer != ImageIndex::ENTIRE_LEVEL) + { + if (mCurrentLayer < maxLayer()-1) + { + mCurrentLayer++; + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + } + else if (mCurrentMip < mMipRange.end-1) + { + mCurrentMip++; + mCurrentLayer = mLayerRange.start; + } + + return value; +} + +ImageIndex ImageIndexIterator::current() const +{ + ImageIndex value(mType, mCurrentMip, mCurrentLayer); + + if (mType == GL_TEXTURE_CUBE_MAP) + { + value.type = TextureCubeMap::layerIndexToTarget(mCurrentLayer); + } + + return value; +} + +bool ImageIndexIterator::hasNext() const +{ + return (mCurrentMip < mMipRange.end || mCurrentLayer < maxLayer()); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/ImageIndex.h b/src/3rdparty/angle/src/libGLESv2/ImageIndex.h index 9f2df88061..8bb14fd555 100644 --- a/src/3rdparty/angle/src/libGLESv2/ImageIndex.h +++ b/src/3rdparty/angle/src/libGLESv2/ImageIndex.h @@ -10,6 +10,7 @@ #define LIBGLESV2_IMAGE_INDEX_H_ #include "angle_gl.h" +#include "common/mathutil.h" namespace gl { @@ -20,6 +21,7 @@ struct ImageIndex GLint mipIndex; GLint layerIndex; + ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); ImageIndex(const ImageIndex &other); ImageIndex &operator=(const ImageIndex &other); @@ -29,11 +31,36 @@ struct ImageIndex static ImageIndex MakeCube(GLenum target, GLint mipIndex); static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex); static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL); + static ImageIndex MakeInvalid(); static const GLint ENTIRE_LEVEL = static_cast(-1); +}; + +class ImageIndexIterator +{ + public: + static ImageIndexIterator Make2D(GLint minMip, GLint maxMip); + static ImageIndexIterator MakeCube(GLint minMip, GLint maxMip); + static ImageIndexIterator Make3D(GLint minMip, GLint maxMip, GLint minLayer, GLint maxLayer); + static ImageIndexIterator Make2DArray(GLint minMip, GLint maxMip, const GLsizei *layerCounts); + + ImageIndex next(); + ImageIndex current() const; + bool hasNext() const; private: - ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn); + + ImageIndexIterator(GLenum type, const rx::Range &mipRange, + const rx::Range &layerRange, const GLsizei *layerCounts); + + GLint maxLayer() const; + + GLenum mType; + rx::Range mMipRange; + rx::Range mLayerRange; + const GLsizei *mLayerCounts; + GLint mCurrentMip; + GLint mCurrentLayer; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/Program.cpp b/src/3rdparty/angle/src/libGLESv2/Program.cpp index 9bfda09a64..3faa8c56f6 100644 --- a/src/3rdparty/angle/src/libGLESv2/Program.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Program.cpp @@ -244,7 +244,7 @@ void Program::bindAttributeLocation(GLuint index, const char *name) // Links the HLSL code of the vertex and pixel shader by matching up their varyings, // compiling them into binaries, determining the attribute mappings, and collecting // a list of uniforms -bool Program::link(const Caps &caps) +Error Program::link(const Data &data) { unlink(false); @@ -252,10 +252,15 @@ bool Program::link(const Caps &caps) resetUniformBlockBindings(); mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, - mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps); + LinkResult result = mProgramBinary->link(data, mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader, + mTransformFeedbackVaryings, mTransformFeedbackBufferMode); + if (result.error.isError()) + { + return result.error; + } - return mLinked; + mLinked = result.linkSuccess; + return gl::Error(GL_NO_ERROR); } int AttributeBindings::getAttributeBinding(const std::string &name) const @@ -303,21 +308,22 @@ ProgramBinary* Program::getProgramBinary() const return mProgramBinary.get(); } -bool Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length) +Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length) { unlink(false); mInfoLog.reset(); mProgramBinary.set(new ProgramBinary(mRenderer->createProgram())); - mLinked = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); - - if (!mLinked) + LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length); + if (result.error.isError()) { mProgramBinary.set(NULL); + return result.error; } - return mLinked; + mLinked = result.linkSuccess; + return Error(GL_NO_ERROR); } void Program::release() diff --git a/src/3rdparty/angle/src/libGLESv2/Program.h b/src/3rdparty/angle/src/libGLESv2/Program.h index 6528dd1191..b92349eeef 100644 --- a/src/3rdparty/angle/src/libGLESv2/Program.h +++ b/src/3rdparty/angle/src/libGLESv2/Program.h @@ -29,6 +29,7 @@ class Renderer; namespace gl { struct Caps; +struct Data; class ResourceManager; class Shader; @@ -77,9 +78,9 @@ class Program void bindAttributeLocation(GLuint index, const char *name); - bool link(const Caps &caps); + Error link(const Data &data); bool isLinked(); - bool setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length); + Error setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length); ProgramBinary *getProgramBinary() const; int getInfoLogLength() const; diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp index 3f6d9e0ef9..6d64b38b56 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp @@ -23,13 +23,11 @@ #include "libGLESv2/Shader.h" #include "libGLESv2/Program.h" #include "libGLESv2/renderer/ProgramImpl.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/d3d/DynamicHLSL.h" #include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/d3d/VertexDataManager.h" #include "libGLESv2/Context.h" #include "libGLESv2/Buffer.h" #include "common/blocklayout.h" +#include "common/features.h" namespace gl { @@ -37,36 +35,6 @@ namespace gl namespace { -GLenum GetTextureType(GLenum samplerType) -{ - switch (samplerType) - { - case GL_SAMPLER_2D: - case GL_INT_SAMPLER_2D: - case GL_UNSIGNED_INT_SAMPLER_2D: - case GL_SAMPLER_2D_SHADOW: - return GL_TEXTURE_2D; - case GL_SAMPLER_3D: - case GL_INT_SAMPLER_3D: - case GL_UNSIGNED_INT_SAMPLER_3D: - return GL_TEXTURE_3D; - case GL_SAMPLER_CUBE: - case GL_SAMPLER_CUBE_SHADOW: - return GL_TEXTURE_CUBE_MAP; - case GL_INT_SAMPLER_CUBE: - case GL_UNSIGNED_INT_SAMPLER_CUBE: - return GL_TEXTURE_CUBE_MAP; - case GL_SAMPLER_2D_ARRAY: - case GL_INT_SAMPLER_2D_ARRAY: - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - case GL_SAMPLER_2D_ARRAY_SHADOW: - return GL_TEXTURE_2D_ARRAY; - default: UNREACHABLE(); - } - - return GL_TEXTURE_2D; -} - unsigned int ParseAndStripArrayIndex(std::string* name) { unsigned int subscript = GL_INVALID_INDEX; @@ -83,52 +51,6 @@ unsigned int ParseAndStripArrayIndex(std::string* name) return subscript; } -void GetDefaultInputLayoutFromShader(const std::vector &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) -{ - size_t layoutIndex = 0; - for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) - { - ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS); - - const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; - - if (shaderAttr.type != GL_NONE) - { - GLenum transposedType = TransposeMatrixType(shaderAttr.type); - - for (size_t rowIndex = 0; static_cast(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++) - { - VertexFormat *defaultFormat = &inputLayout[layoutIndex]; - - defaultFormat->mType = VariableComponentType(transposedType); - defaultFormat->mNormalized = false; - defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool - defaultFormat->mComponents = VariableColumnCount(transposedType); - } - } - } -} - -std::vector GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) -{ - std::vector defaultPixelOutput(1); - - ASSERT(!shaderOutputVars.empty()); - defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex; - - return defaultPixelOutput; -} - -bool IsRowMajorLayout(const sh::InterfaceBlockField &var) -{ - return var.isRowMajorLayout; -} - -bool IsRowMajorLayout(const sh::ShaderVariable &var) -{ - return false; -} - } VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index) @@ -136,47 +58,6 @@ VariableLocation::VariableLocation(const std::string &name, unsigned int element { } -ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[], - const GLenum signature[], - rx::ShaderExecutable *shaderExecutable) - : mShaderExecutable(shaderExecutable) -{ - for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) - { - mInputs[attributeIndex] = inputLayout[attributeIndex]; - mSignature[attributeIndex] = signature[attributeIndex]; - } -} - -ProgramBinary::VertexExecutable::~VertexExecutable() -{ - SafeDelete(mShaderExecutable); -} - -bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const -{ - for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) - { - if (mSignature[attributeIndex] != signature[attributeIndex]) - { - return false; - } - } - - return true; -} - -ProgramBinary::PixelExecutable::PixelExecutable(const std::vector &outputSignature, rx::ShaderExecutable *shaderExecutable) - : mOutputSignature(outputSignature), - mShaderExecutable(shaderExecutable) -{ -} - -ProgramBinary::PixelExecutable::~PixelExecutable() -{ - SafeDelete(mShaderExecutable); -} - LinkedVarying::LinkedVarying() { } @@ -187,17 +68,17 @@ LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, { } +LinkResult::LinkResult(bool linkSuccess, const Error &error) + : linkSuccess(linkSuccess), + error(error) +{ +} + unsigned int ProgramBinary::mCurrentSerial = 1; ProgramBinary::ProgramBinary(rx::ProgramImpl *impl) : RefCountObject(0), mProgram(impl), - mGeometryExecutable(NULL), - mUsedVertexSamplerRange(0), - mUsedPixelSamplerRange(0), - mUsesPointSize(false), - mShaderVersion(100), - mDirtySamplerMapping(true), mValidated(false), mSerial(issueSerial()) { @@ -220,103 +101,11 @@ unsigned int ProgramBinary::getSerial() const return mSerial; } -int ProgramBinary::getShaderVersion() const -{ - return mShaderVersion; -} - unsigned int ProgramBinary::issueSerial() { return mCurrentSerial++; } -rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo) -{ - std::vector outputs; - - const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender(); - - for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) - { - const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; - - if (colorbuffer) - { - outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); - } - else - { - outputs.push_back(GL_NONE); - } - } - - return getPixelExecutableForOutputLayout(outputs); -} - -rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector &outputSignature) -{ - for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) - { - if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) - { - return mPixelExecutables[executableIndex]->shaderExecutable(); - } - } - - InfoLog tempInfoLog; - rx::ShaderExecutable *pixelExecutable = mProgram->getPixelExecutableForOutputLayout(tempInfoLog, outputSignature, - mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); - - if (!pixelExecutable) - { - std::vector tempCharBuffer(tempInfoLog.getLength() + 3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); - } - else - { - mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); - } - - return pixelExecutable; -} - -rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]) -{ - GLenum signature[MAX_VERTEX_ATTRIBS]; - mProgram->getDynamicHLSL()->getInputLayoutSignature(inputLayout, signature); - - for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) - { - if (mVertexExecutables[executableIndex]->matchesSignature(signature)) - { - return mVertexExecutables[executableIndex]->shaderExecutable(); - } - } - - InfoLog tempInfoLog; - rx::ShaderExecutable *vertexExecutable = mProgram->getVertexExecutableForInputLayout(tempInfoLog, inputLayout, mShaderAttributes, - mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); - - if (!vertexExecutable) - { - std::vector tempCharBuffer(tempInfoLog.getLength()+3); - tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); - ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); - } - else - { - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); - } - - return vertexExecutable; -} - -rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const -{ - return mGeometryExecutable; -} - GLuint ProgramBinary::getAttributeLocation(const char *name) { if (name) @@ -343,157 +132,42 @@ int ProgramBinary::getSemanticIndex(int attributeIndex) // Returns one more than the highest sampler index used. GLint ProgramBinary::getUsedSamplerRange(SamplerType type) { - switch (type) - { - case SAMPLER_PIXEL: - return mUsedPixelSamplerRange; - case SAMPLER_VERTEX: - return mUsedVertexSamplerRange; - default: - UNREACHABLE(); - return 0; - } + return mProgram->getUsedSamplerRange(type); } bool ProgramBinary::usesPointSize() const { - return mUsesPointSize; -} - -bool ProgramBinary::usesPointSpriteEmulation() const -{ - return mUsesPointSize && mProgram->getRenderer()->getMajorShaderModel() >= 4; -} - -bool ProgramBinary::usesGeometryShader() const -{ - return usesPointSpriteEmulation(); + return mProgram->usesPointSize(); } GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps) { - GLint logicalTextureUnit = -1; - - switch (type) - { - case SAMPLER_PIXEL: - ASSERT(samplerIndex < caps.maxTextureImageUnits); - if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) - { - logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; - } - break; - case SAMPLER_VERTEX: - ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); - if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) - { - logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; - } - break; - default: UNREACHABLE(); - } - - if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast(caps.maxCombinedTextureImageUnits)) - { - return logicalTextureUnit; - } - - return -1; + return mProgram->getSamplerMapping(type, samplerIndex, caps); } -// Returns the texture type for a given Direct3D 9 sampler type and -// index (0-15 for the pixel shader and 0-3 for the vertex shader). GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex) { - switch (type) - { - case SAMPLER_PIXEL: - ASSERT(samplerIndex < mSamplersPS.size()); - ASSERT(mSamplersPS[samplerIndex].active); - return mSamplersPS[samplerIndex].textureType; - case SAMPLER_VERTEX: - ASSERT(samplerIndex < mSamplersVS.size()); - ASSERT(mSamplersVS[samplerIndex].active); - return mSamplersVS[samplerIndex].textureType; - default: UNREACHABLE(); - } - - return GL_TEXTURE_2D; + return mProgram->getSamplerTextureType(type, samplerIndex); } GLint ProgramBinary::getUniformLocation(std::string name) { - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniforms = mUniformIndex.size(); - for (unsigned int location = 0; location < numUniforms; location++) - { - if (mUniformIndex[location].name == name) - { - const int index = mUniformIndex[location].index; - const bool isArray = mUniforms[index]->isArray(); - - if ((isArray && mUniformIndex[location].element == subscript) || - (subscript == GL_INVALID_INDEX)) - { - return location; - } - } - } - - return -1; + return mProgram->getUniformLocation(name); } GLuint ProgramBinary::getUniformIndex(std::string name) { - unsigned int subscript = ParseAndStripArrayIndex(&name); - - // The app is not allowed to specify array indices other than 0 for arrays of basic types - if (subscript != 0 && subscript != GL_INVALID_INDEX) - { - return GL_INVALID_INDEX; - } - - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) - { - if (mUniforms[index]->name == name) - { - if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) - { - return index; - } - } - } - - return GL_INVALID_INDEX; + return mProgram->getUniformIndex(name); } GLuint ProgramBinary::getUniformBlockIndex(std::string name) { - unsigned int subscript = ParseAndStripArrayIndex(&name); - - unsigned int numUniformBlocks = mUniformBlocks.size(); - for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) - { - const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; - if (uniformBlock.name == name) - { - const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); - if (subscript == uniformBlock.elementIndex || arrayElementZero) - { - return blockIndex; - } - } - } - - return GL_INVALID_INDEX; + return mProgram->getUniformBlockIndex(name); } UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex) { - ASSERT(blockIndex < mUniformBlocks.size()); - return mUniformBlocks[blockIndex]; + return mProgram->getUniformBlockByIndex(blockIndex); } GLint ProgramBinary::getFragDataLocation(const char *name) const @@ -517,524 +191,129 @@ GLint ProgramBinary::getFragDataLocation(const char *name) const size_t ProgramBinary::getTransformFeedbackVaryingCount() const { - return mTransformFeedbackLinkedVaryings.size(); + return mProgram->getTransformFeedbackLinkedVaryings().size(); } const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const { - return mTransformFeedbackLinkedVaryings[idx]; + return mProgram->getTransformFeedbackLinkedVaryings()[idx]; } GLenum ProgramBinary::getTransformFeedbackBufferMode() const { - return mTransformFeedbackBufferMode; + return mProgram->getTransformFeedbackBufferMode(); } -template -static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) -{ - ASSERT(dest != NULL); - ASSERT(dirtyFlag != NULL); - - *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); - *dest = source; +void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) { + mProgram->setUniform1fv(location, count, v); } -template -void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) -{ - const int components = VariableComponentCount(targetUniformType); - const GLenum targetBoolType = VariableBoolVectorType(targetUniformType); - - LinkedUniform *targetUniform = getUniformByLocation(location); - - int elementCount = targetUniform->elementCount(); - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - - if (targetUniform->type == targetUniformType) - { - T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - T *dest = target + (i * 4); - const T *source = v + (i * components); - - for (int c = 0; c < components; c++) - { - SetIfDirty(dest + c, source[c], &targetUniform->dirty); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, T(0), &targetUniform->dirty); - } - } - } - else if (targetUniform->type == targetBoolType) - { - GLint *boolParams = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - for (int i = 0; i < count; i++) - { - GLint *dest = boolParams + (i * 4); - const T *source = v + (i * components); - - for (int c = 0; c < components; c++) - { - SetIfDirty(dest + c, (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); - } - for (int c = components; c < 4; c++) - { - SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); - } - } - } - else if (IsSampler(targetUniform->type)) - { - ASSERT(targetUniformType == GL_INT); - - GLint *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; - - bool wasDirty = targetUniform->dirty; - - for (int i = 0; i < count; i++) - { - GLint *dest = target + (i * 4); - const GLint *source = reinterpret_cast(v) + (i * components); - - SetIfDirty(dest + 0, source[0], &targetUniform->dirty); - SetIfDirty(dest + 1, 0, &targetUniform->dirty); - SetIfDirty(dest + 2, 0, &targetUniform->dirty); - SetIfDirty(dest + 3, 0, &targetUniform->dirty); - } - - if (!wasDirty && targetUniform->dirty) - { - mDirtySamplerMapping = true; - } - } - else UNREACHABLE(); +void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) { + mProgram->setUniform2fv(location, count, v); } -void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) -{ - setUniform(location, count, v, GL_FLOAT); +void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) { + mProgram->setUniform3fv(location, count, v); } -void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC2); +void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) { + mProgram->setUniform4fv(location, count, v); } -void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC3); +void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) { + mProgram->setUniform1iv(location, count, v); } -void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) -{ - setUniform(location, count, v, GL_FLOAT_VEC4); +void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) { + mProgram->setUniform2iv(location, count, v); } -template -bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) -{ - bool dirty = false; - int copyWidth = std::min(targetHeight, srcWidth); - int copyHeight = std::min(targetWidth, srcHeight); - - for (int x = 0; x < copyWidth; x++) - { - for (int y = 0; y < copyHeight; y++) - { - SetIfDirty(target + (x * targetWidth + y), static_cast(value[y * srcWidth + x]), &dirty); - } - } - // clear unfilled right side - for (int y = 0; y < copyWidth; y++) - { - for (int x = copyHeight; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyWidth; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - - return dirty; +void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) { + mProgram->setUniform3iv(location, count, v); } -template -bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) -{ - bool dirty = false; - int copyWidth = std::min(targetWidth, srcWidth); - int copyHeight = std::min(targetHeight, srcHeight); - - for (int y = 0; y < copyHeight; y++) - { - for (int x = 0; x < copyWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), &dirty); - } - } - // clear unfilled right side - for (int y = 0; y < copyHeight; y++) - { - for (int x = copyWidth; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - // clear unfilled bottom. - for (int y = copyHeight; y < targetHeight; y++) - { - for (int x = 0; x < targetWidth; x++) - { - SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); - } - } - - return dirty; +void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) { + mProgram->setUniform4iv(location, count, v); } -template -void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) -{ - LinkedUniform *targetUniform = getUniformByLocation(location); - - int elementCount = targetUniform->elementCount(); - - count = std::min(elementCount - (int)mUniformIndex[location].element, count); - const unsigned int targetMatrixStride = (4 * rows); - GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); - - for (int i = 0; i < count; i++) - { - // Internally store matrices as transposed versions to accomodate HLSL matrix indexing - if (transpose == GL_FALSE) - { - targetUniform->dirty = transposeMatrix(target, value, 4, rows, rows, cols) || targetUniform->dirty; - } - else - { - targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; - } - target += targetMatrixStride; - value += cols * rows; - } +void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) { + mProgram->setUniform1uiv(location, count, v); } -void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); +void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) { + mProgram->setUniform2uiv(location, count, v); } -void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) { + mProgram->setUniform3uiv(location, count, v); } -void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) { + mProgram->setUniform4uiv(location, count, v); } -void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix2fv(location, count, transpose, v); } -void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix3fv(location, count, transpose, v); } -void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix4fv(location, count, transpose, v); } -void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix2x3fv(location, count, transpose, v); } -void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); +void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix2x4fv(location, count, transpose, v); } -void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) -{ - setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix3x2fv(location, count, transpose, v); } -void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT); +void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix3x4fv(location, count, transpose, v); } -void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC2); +void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix4x2fv(location, count, transpose, v); } -void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC3); +void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) { + mProgram->setUniformMatrix4x3fv(location, count, transpose, v); } -void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) -{ - setUniform(location, count, v, GL_INT_VEC4); +void ProgramBinary::getUniformfv(GLint location, GLfloat *v) { + mProgram->getUniformfv(location, v); } -void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT); +void ProgramBinary::getUniformiv(GLint location, GLint *v) { + mProgram->getUniformiv(location, v); } -void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); -} - -void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); -} - -void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) -{ - setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); -} - -template -void ProgramBinary::getUniformv(GLint location, T *params, GLenum uniformType) -{ - LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; - - if (IsMatrixType(targetUniform->type)) - { - const int rows = VariableRowCount(targetUniform->type); - const int cols = VariableColumnCount(targetUniform->type); - transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); - } - else if (uniformType == VariableComponentType(targetUniform->type)) - { - unsigned int size = VariableComponentCount(targetUniform->type); - memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), - size * sizeof(T)); - } - else - { - unsigned int size = VariableComponentCount(targetUniform->type); - switch (VariableComponentType(targetUniform->type)) - { - case GL_BOOL: - { - GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = (boolParams[i] == GL_FALSE) ? static_cast(0) : static_cast(1); - } - } - break; - - case GL_FLOAT: - { - GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(floatParams[i]); - } - } - break; - - case GL_INT: - { - GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(intParams[i]); - } - } - break; - - case GL_UNSIGNED_INT: - { - GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; - - for (unsigned int i = 0; i < size; i++) - { - params[i] = static_cast(uintParams[i]); - } - } - break; - - default: UNREACHABLE(); - } - } -} - -void ProgramBinary::getUniformfv(GLint location, GLfloat *params) -{ - getUniformv(location, params, GL_FLOAT); -} - -void ProgramBinary::getUniformiv(GLint location, GLint *params) -{ - getUniformv(location, params, GL_INT); -} - -void ProgramBinary::getUniformuiv(GLint location, GLuint *params) -{ - getUniformv(location, params, GL_UNSIGNED_INT); -} - -void ProgramBinary::dirtyAllUniforms() -{ - unsigned int numUniforms = mUniforms.size(); - for (unsigned int index = 0; index < numUniforms; index++) - { - mUniforms[index]->dirty = true; - } +void ProgramBinary::getUniformuiv(GLint location, GLuint *v) { + mProgram->getUniformuiv(location, v); } void ProgramBinary::updateSamplerMapping() { - if (!mDirtySamplerMapping) - { - return; - } - - mDirtySamplerMapping = false; - - // Retrieve sampler uniform values - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - LinkedUniform *targetUniform = mUniforms[uniformIndex]; - - if (targetUniform->dirty) - { - if (IsSampler(targetUniform->type)) - { - int count = targetUniform->elementCount(); - GLint (*v)[4] = reinterpret_cast(targetUniform->data); - - if (targetUniform->isReferencedByFragmentShader()) - { - unsigned int firstIndex = targetUniform->psRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersPS.size()) - { - ASSERT(mSamplersPS[samplerIndex].active); - mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - - if (targetUniform->isReferencedByVertexShader()) - { - unsigned int firstIndex = targetUniform->vsRegisterIndex; - - for (int i = 0; i < count; i++) - { - unsigned int samplerIndex = firstIndex + i; - - if (samplerIndex < mSamplersVS.size()) - { - ASSERT(mSamplersVS[samplerIndex].active); - mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; - } - } - } - } - } - } + return mProgram->updateSamplerMapping(); } // Applies all the uniforms set for this program object to the renderer Error ProgramBinary::applyUniforms() { - updateSamplerMapping(); - - Error error = mProgram->getRenderer()->applyUniforms(*this); - if (error.isError()) - { - return error; - } - - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - mUniforms[uniformIndex]->dirty = false; - } - - return gl::Error(GL_NO_ERROR); + return mProgram->applyUniforms(); } Error ProgramBinary::applyUniformBuffers(const std::vector boundBuffers, const Caps &caps) { - const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL}; - const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL}; - - const unsigned int reservedBuffersInVS = mProgram->getRenderer()->getReservedVertexUniformBuffers(); - const unsigned int reservedBuffersInFS = mProgram->getRenderer()->getReservedFragmentUniformBuffers(); - - ASSERT(boundBuffers.size() == mUniformBlocks.size()); - - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) - { - UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex); - gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex]; - - ASSERT(uniformBlock && uniformBuffer); - - if (uniformBuffer->getSize() < uniformBlock->dataSize) - { - // undefined behaviour - return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."); - } - - // Unnecessary to apply an unreferenced standard or shared UBO - if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) - { - continue; - } - - if (uniformBlock->isReferencedByVertexShader()) - { - unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; - ASSERT(vertexUniformBuffers[registerIndex] == NULL); - ASSERT(registerIndex < caps.maxVertexUniformBlocks); - vertexUniformBuffers[registerIndex] = uniformBuffer; - } - - if (uniformBlock->isReferencedByFragmentShader()) - { - unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; - ASSERT(fragmentUniformBuffers[registerIndex] == NULL); - ASSERT(registerIndex < caps.maxFragmentUniformBlocks); - fragmentUniformBuffers[registerIndex] = uniformBuffer; - } - } - - return mProgram->getRenderer()->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers); + return mProgram->applyUniformBuffers(boundBuffers, caps); } bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader) @@ -1082,10 +361,10 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shade return true; } -bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length) +LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length) { -#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD - return false; +#if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_DISABLED + return LinkResult(false, Error(GL_NO_ERROR)); #else ASSERT(binaryFormat == mProgram->getBinaryFormat()); @@ -1097,7 +376,7 @@ bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *bina if (format != mProgram->getBinaryFormat()) { infoLog.append("Invalid program binary format."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } int majorVersion = stream.readInt(); @@ -1105,7 +384,7 @@ bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *bina if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION) { infoLog.append("Invalid program binary version."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } unsigned char commitString[ANGLE_COMMIT_HASH_SIZE]; @@ -1113,250 +392,38 @@ bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *bina if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0) { infoLog.append("Invalid program binary version."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } int compileFlags = stream.readInt(); if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL) { infoLog.append("Mismatched compilation flags."); - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i) { stream.readInt(&mLinkedAttribute[i].type); stream.readString(&mLinkedAttribute[i].name); - stream.readInt(&mShaderAttributes[i].type); - stream.readString(&mShaderAttributes[i].name); + stream.readInt(&mProgram->getShaderAttributes()[i].type); + stream.readString(&mProgram->getShaderAttributes()[i].name); stream.readInt(&mSemanticIndex[i]); } initAttributesByLayout(); - const unsigned int psSamplerCount = stream.readInt(); - for (unsigned int i = 0; i < psSamplerCount; ++i) + LinkResult result = mProgram->load(infoLog, &stream); + if (result.error.isError() || !result.linkSuccess) { - Sampler sampler; - stream.readBool(&sampler.active); - stream.readInt(&sampler.logicalTextureUnit); - stream.readInt(&sampler.textureType); - mSamplersPS.push_back(sampler); - } - const unsigned int vsSamplerCount = stream.readInt(); - for (unsigned int i = 0; i < vsSamplerCount; ++i) - { - Sampler sampler; - stream.readBool(&sampler.active); - stream.readInt(&sampler.logicalTextureUnit); - stream.readInt(&sampler.textureType); - mSamplersVS.push_back(sampler); + return result; } - stream.readInt(&mUsedVertexSamplerRange); - stream.readInt(&mUsedPixelSamplerRange); - stream.readBool(&mUsesPointSize); - stream.readInt(&mShaderVersion); - - const unsigned int uniformCount = stream.readInt(); - if (stream.error()) - { - infoLog.append("Invalid program binary."); - return false; - } - - mUniforms.resize(uniformCount); - for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) - { - GLenum type = stream.readInt(); - GLenum precision = stream.readInt(); - std::string name = stream.readString(); - unsigned int arraySize = stream.readInt(); - int blockIndex = stream.readInt(); - - int offset = stream.readInt(); - int arrayStride = stream.readInt(); - int matrixStride = stream.readInt(); - bool isRowMajorMatrix = stream.readBool(); - - const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); - - LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); - - stream.readInt(&uniform->psRegisterIndex); - stream.readInt(&uniform->vsRegisterIndex); - stream.readInt(&uniform->registerCount); - stream.readInt(&uniform->registerElement); - - mUniforms[uniformIndex] = uniform; - } - - unsigned int uniformBlockCount = stream.readInt(); - if (stream.error()) - { - infoLog.append("Invalid program binary."); - return false; - } - - mUniformBlocks.resize(uniformBlockCount); - for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) - { - std::string name = stream.readString(); - unsigned int elementIndex = stream.readInt(); - unsigned int dataSize = stream.readInt(); - - UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize); - - stream.readInt(&uniformBlock->psRegisterIndex); - stream.readInt(&uniformBlock->vsRegisterIndex); - - unsigned int numMembers = stream.readInt(); - uniformBlock->memberUniformIndexes.resize(numMembers); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) - { - stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); - } - - mUniformBlocks[uniformBlockIndex] = uniformBlock; - } - - const unsigned int uniformIndexCount = stream.readInt(); - if (stream.error()) - { - infoLog.append("Invalid program binary."); - return false; - } - - mUniformIndex.resize(uniformIndexCount); - for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) - { - stream.readString(&mUniformIndex[uniformIndexIndex].name); - stream.readInt(&mUniformIndex[uniformIndexIndex].element); - stream.readInt(&mUniformIndex[uniformIndexIndex].index); - } - - stream.readInt(&mTransformFeedbackBufferMode); - const unsigned int transformFeedbackVaryingCount = stream.readInt(); - mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); - for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) - { - LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; - - stream.readString(&varying.name); - stream.readInt(&varying.type); - stream.readInt(&varying.size); - stream.readString(&varying.semanticName); - stream.readInt(&varying.semanticIndex); - stream.readInt(&varying.semanticIndexCount); - } - - const unsigned int vertexShaderCount = stream.readInt(); - for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) - { - VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]; - - for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++) - { - VertexFormat *vertexInput = &inputLayout[inputIndex]; - stream.readInt(&vertexInput->mType); - stream.readInt(&vertexInput->mNormalized); - stream.readInt(&vertexInput->mComponents); - stream.readBool(&vertexInput->mPureInteger); - } - - unsigned int vertexShaderSize = stream.readInt(); - const unsigned char *vertexShaderFunction = reinterpret_cast(binary) + stream.offset(); - rx::ShaderExecutable *shaderExecutable = mProgram->getRenderer()->loadExecutable(reinterpret_cast(vertexShaderFunction), - vertexShaderSize, rx::SHADER_VERTEX, - mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); - if (!shaderExecutable) - { - infoLog.append("Could not create vertex shader."); - return false; - } - - // generated converted input layout - GLenum signature[MAX_VERTEX_ATTRIBS]; - mProgram->getDynamicHLSL()->getInputLayoutSignature(inputLayout, signature); - - // add new binary - mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); - - stream.skip(vertexShaderSize); - } - - const size_t pixelShaderCount = stream.readInt(); - for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) - { - const size_t outputCount = stream.readInt(); - std::vector outputs(outputCount); - for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) - { - stream.readInt(&outputs[outputIndex]); - } - - const size_t pixelShaderSize = stream.readInt(); - const unsigned char *pixelShaderFunction = reinterpret_cast(binary) + stream.offset(); - rx::Renderer *renderer = mProgram->getRenderer(); - rx::ShaderExecutable *shaderExecutable = renderer->loadExecutable(pixelShaderFunction, pixelShaderSize, - rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); - - if (!shaderExecutable) - { - infoLog.append("Could not create pixel shader."); - return false; - } - - // add new binary - mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); - - stream.skip(pixelShaderSize); - } - - unsigned int geometryShaderSize = stream.readInt(); - - if (geometryShaderSize > 0) - { - const char *geometryShaderFunction = (const char*) binary + stream.offset(); - rx::Renderer *renderer = mProgram->getRenderer(); - mGeometryExecutable = renderer->loadExecutable(reinterpret_cast(geometryShaderFunction), - geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS)); - - if (!mGeometryExecutable) - { - infoLog.append("Could not create geometry shader."); - return false; - } - stream.skip(geometryShaderSize); - } - - if (!mProgram->load(infoLog, &stream)) - { - return false; - } - - const char *ptr = (const char*) binary + stream.offset(); - - const GUID *binaryIdentifier = (const GUID *) ptr; - ptr += sizeof(GUID); - - GUID identifier = mProgram->getRenderer()->getAdapterIdentifier(); - if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0) - { - infoLog.append("Invalid program binary."); - return false; - } - - mProgram->initializeUniformStorage(mUniforms); - - return true; -#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD + return LinkResult(true, Error(GL_NO_ERROR)); +#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED } -bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) +Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) { if (binaryFormat) { @@ -1375,168 +442,27 @@ bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GL { stream.writeInt(mLinkedAttribute[i].type); stream.writeString(mLinkedAttribute[i].name); - stream.writeInt(mShaderAttributes[i].type); - stream.writeString(mShaderAttributes[i].name); + stream.writeInt(mProgram->getShaderAttributes()[i].type); + stream.writeString(mProgram->getShaderAttributes()[i].name); stream.writeInt(mSemanticIndex[i]); } - stream.writeInt(mSamplersPS.size()); - for (unsigned int i = 0; i < mSamplersPS.size(); ++i) - { - stream.writeInt(mSamplersPS[i].active); - stream.writeInt(mSamplersPS[i].logicalTextureUnit); - stream.writeInt(mSamplersPS[i].textureType); - } - - stream.writeInt(mSamplersVS.size()); - for (unsigned int i = 0; i < mSamplersVS.size(); ++i) - { - stream.writeInt(mSamplersVS[i].active); - stream.writeInt(mSamplersVS[i].logicalTextureUnit); - stream.writeInt(mSamplersVS[i].textureType); - } - - stream.writeInt(mUsedVertexSamplerRange); - stream.writeInt(mUsedPixelSamplerRange); - stream.writeInt(mUsesPointSize); - stream.writeInt(mShaderVersion); - - stream.writeInt(mUniforms.size()); - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) - { - const LinkedUniform &uniform = *mUniforms[uniformIndex]; - - stream.writeInt(uniform.type); - stream.writeInt(uniform.precision); - stream.writeString(uniform.name); - stream.writeInt(uniform.arraySize); - stream.writeInt(uniform.blockIndex); - - stream.writeInt(uniform.blockInfo.offset); - stream.writeInt(uniform.blockInfo.arrayStride); - stream.writeInt(uniform.blockInfo.matrixStride); - stream.writeInt(uniform.blockInfo.isRowMajorMatrix); - - stream.writeInt(uniform.psRegisterIndex); - stream.writeInt(uniform.vsRegisterIndex); - stream.writeInt(uniform.registerCount); - stream.writeInt(uniform.registerElement); - } - - stream.writeInt(mUniformBlocks.size()); - for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) - { - const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; - - stream.writeString(uniformBlock.name); - stream.writeInt(uniformBlock.elementIndex); - stream.writeInt(uniformBlock.dataSize); - - stream.writeInt(uniformBlock.memberUniformIndexes.size()); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) - { - stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); - } - - stream.writeInt(uniformBlock.psRegisterIndex); - stream.writeInt(uniformBlock.vsRegisterIndex); - } - - stream.writeInt(mUniformIndex.size()); - for (size_t i = 0; i < mUniformIndex.size(); ++i) - { - stream.writeString(mUniformIndex[i].name); - stream.writeInt(mUniformIndex[i].element); - stream.writeInt(mUniformIndex[i].index); - } - - stream.writeInt(mTransformFeedbackBufferMode); - stream.writeInt(mTransformFeedbackLinkedVaryings.size()); - for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) - { - const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; - - stream.writeString(varying.name); - stream.writeInt(varying.type); - stream.writeInt(varying.size); - stream.writeString(varying.semanticName); - stream.writeInt(varying.semanticIndex); - stream.writeInt(varying.semanticIndexCount); - } - - stream.writeInt(mVertexExecutables.size()); - for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) - { - VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; - - for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) - { - const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; - stream.writeInt(vertexInput.mType); - stream.writeInt(vertexInput.mNormalized); - stream.writeInt(vertexInput.mComponents); - stream.writeInt(vertexInput.mPureInteger); - } - - size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); - stream.writeInt(vertexShaderSize); - - const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); - stream.writeBytes(vertexBlob, vertexShaderSize); - } - - stream.writeInt(mPixelExecutables.size()); - for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) - { - PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; - - const std::vector outputs = pixelExecutable->outputSignature(); - stream.writeInt(outputs.size()); - for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) - { - stream.writeInt(outputs[outputIndex]); - } - - size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); - stream.writeInt(pixelShaderSize); - - const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); - stream.writeBytes(pixelBlob, pixelShaderSize); - } - - size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; - stream.writeInt(geometryShaderSize); - - if (mGeometryExecutable != NULL && geometryShaderSize > 0) - { - const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); - stream.writeBytes(geometryBlob, geometryShaderSize); - } - - if (!mProgram->save(&stream)) - { - if (length) - { - *length = 0; - } - - return false; - } - - GUID identifier = mProgram->getRenderer()->getAdapterIdentifier(); + mProgram->save(&stream); GLsizei streamLength = stream.length(); const void *streamData = stream.data(); - GLsizei totalLength = streamLength + sizeof(GUID); - if (totalLength > bufSize) + if (streamLength > bufSize) { if (length) { *length = 0; } - return false; + // TODO: This should be moved to the validation layer but computing the size of the binary before saving + // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate + // sizes and then copy it. + return Error(GL_INVALID_OPERATION); } if (binary) @@ -1546,129 +472,197 @@ bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GL memcpy(ptr, streamData, streamLength); ptr += streamLength; - memcpy(ptr, &identifier, sizeof(GUID)); - ptr += sizeof(GUID); - - ASSERT(ptr - totalLength == binary); + ASSERT(ptr - streamLength == binary); } if (length) { - *length = totalLength; + *length = streamLength; } - return true; + return Error(GL_NO_ERROR); } GLint ProgramBinary::getLength() { GLint length; - if (save(NULL, NULL, INT_MAX, &length)) - { - return length; - } - else + Error error = save(NULL, NULL, INT_MAX, &length); + if (error.isError()) { return 0; } + + return length; } -bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, - const std::vector& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps) +LinkResult ProgramBinary::link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings, + Shader *fragmentShader, Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode) { if (!fragmentShader || !fragmentShader->isCompiled()) { - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER); if (!vertexShader || !vertexShader->isCompiled()) { - return false; + return LinkResult(false, Error(GL_NO_ERROR)); } ASSERT(vertexShader->getType() == GL_VERTEX_SHADER); reset(); - mSamplersPS.resize(caps.maxTextureImageUnits); - mSamplersVS.resize(caps.maxVertexTextureImageUnits); - - mTransformFeedbackBufferMode = transformFeedbackBufferMode; - - rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); - - mShaderVersion = vertexShaderD3D->getShaderVersion(); - int registers; std::vector linkedVaryings; - if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, ®isters, &linkedVaryings, &mOutputVariables)) + LinkResult result = mProgram->link(data, infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode, + ®isters, &linkedVaryings, &mOutputVariables); + if (result.error.isError() || !result.linkSuccess) { - return false; + return result; } - mUsesPointSize = vertexShaderD3D->usesPointSize(); - - bool success = true; - if (!linkAttributes(infoLog, attributeBindings, vertexShader)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } - if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps)) + if (!mProgram->linkUniforms(infoLog, *vertexShader, *fragmentShader, *data.caps)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } - // special case for gl_DepthRange, the only built-in uniform (also a struct) - if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) + if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, *data.caps)) { - const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); - - mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); - mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); - mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); - } - - if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps)) - { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings, - transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings, caps)) + transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps)) { - success = false; + return LinkResult(false, Error(GL_NO_ERROR)); } - if (success) + // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called, + // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling. + result = mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers); + if (result.error.isError() || !result.linkSuccess) { - VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS]; - GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); - rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout); + infoLog.append("Failed to create D3D shaders."); + reset(); + return result; + } - std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(mProgram->getPixelShaderKey()); - rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput); + return LinkResult(true, Error(GL_NO_ERROR)); +} - if (usesGeometryShader()) +bool ProgramBinary::linkUniformBlocks(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) +{ + const std::vector &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); + const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); + + // Check that interface blocks defined in the vertex and fragment shaders are identical + typedef std::map UniformBlockMap; + UniformBlockMap linkedUniformBlocks; + + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; + linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; + } + + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; + UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); + if (entry != linkedUniformBlocks.end()) { - std::string geometryHLSL = mProgram->getDynamicHLSL()->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); - mGeometryExecutable = mProgram->getRenderer()->compileToExecutable(infoLog, geometryHLSL.c_str(), - rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, - (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), - rx::ANGLE_D3D_WORKAROUND_NONE); - } - - if (!defaultVertexExecutable || !defaultPixelExecutable || (usesGeometryShader() && !mGeometryExecutable)) - { - infoLog.append("Failed to create D3D shaders."); - success = false; - reset(); + const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; + if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) + { + return false; + } } } - return success; + for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex]; + + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps)) + { + return false; + } + } + } + + for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) + { + const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex]; + + // Note: shared and std140 layouts are always considered active + if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) + { + if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps)) + { + return false; + } + } + } + + return true; +} + +bool ProgramBinary::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock) +{ + const char* blockName = vertexInterfaceBlock.name.c_str(); + + // validate blocks for the same member types + if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) + { + infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); + return false; + } + + if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) + { + infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + + if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) + { + infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); + return false; + } + + const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) + { + const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; + const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; + + if (vertexMember.name != fragmentMember.name) + { + infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", + blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); + return false; + } + + std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; + if (!gl::ProgramBinary::linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) + { + return false; + } + } + + return true; } // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices @@ -1688,7 +682,7 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location; - mShaderAttributes[attributeIndex] = attribute; + mProgram->getShaderAttributes()[attributeIndex] = attribute; if (location != -1) // Set by glBindAttribLocation or by location layout qualifier { @@ -1708,7 +702,7 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at // In GLSL 3.00, attribute aliasing produces a link error // In GLSL 1.00, attribute aliasing is allowed - if (mShaderVersion >= 300) + if (mProgram->getShaderVersion() >= 300) { if (!linkedAttribute.name.empty()) { @@ -1856,346 +850,6 @@ bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std return true; } -bool ProgramBinary::linkUniforms(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps) -{ - const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); - const rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); - - const std::vector &vertexUniforms = vertexShader.getUniforms(); - const std::vector &fragmentUniforms = fragmentShader.getUniforms(); - - // Check that uniforms defined in the vertex and fragment shaders are identical - typedef std::map UniformMap; - UniformMap linkedUniforms; - - for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) - { - const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; - linkedUniforms[vertexUniform.name] = &vertexUniform; - } - - for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) - { - const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; - UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); - if (entry != linkedUniforms.end()) - { - const sh::Uniform &vertexUniform = *entry->second; - const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; - if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) - { - return false; - } - } - } - - for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) - { - const sh::Uniform &uniform = vertexUniforms[uniformIndex]; - - if (uniform.staticUse) - { - defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); - } - } - - for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) - { - const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; - - if (uniform.staticUse) - { - defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); - } - } - - if (!indexUniforms(infoLog, caps)) - { - return false; - } - - mProgram->initializeUniformStorage(mUniforms); - - return true; -} - -void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister) -{ - ShShaderOutput outputType = rx::ShaderD3D::getCompilerOutputType(shader); - sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); - encoder.skipRegisters(uniformRegister); - - defineUniform(shader, uniform, uniform.name, &encoder); -} - -void ProgramBinary::defineUniform(GLenum shader, const sh::ShaderVariable &uniform, - const std::string &fullName, sh::HLSLBlockEncoder *encoder) -{ - if (uniform.isStruct()) - { - for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) - { - const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); - - encoder->enterAggregateType(); - - for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) - { - const sh::ShaderVariable &field = uniform.fields[fieldIndex]; - const std::string &fieldFullName = (fullName + elementString + "." + field.name); - - defineUniform(shader, field, fieldFullName, encoder); - } - - encoder->exitAggregateType(); - } - } - else // Not a struct - { - // Arrays are treated as aggregate types - if (uniform.isArray()) - { - encoder->enterAggregateType(); - } - - LinkedUniform *linkedUniform = getUniformByName(fullName); - - if (!linkedUniform) - { - linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, - -1, sh::BlockMemberInfo::getDefaultBlockInfo()); - ASSERT(linkedUniform); - linkedUniform->registerElement = encoder->getCurrentElement(); - mUniforms.push_back(linkedUniform); - } - - ASSERT(linkedUniform->registerElement == encoder->getCurrentElement()); - - if (shader == GL_FRAGMENT_SHADER) - { - linkedUniform->psRegisterIndex = encoder->getCurrentRegister(); - } - else if (shader == GL_VERTEX_SHADER) - { - linkedUniform->vsRegisterIndex = encoder->getCurrentRegister(); - } - else UNREACHABLE(); - - // Advance the uniform offset, to track registers allocation for structs - encoder->encodeType(uniform.type, uniform.arraySize, false); - - // Arrays are treated as aggregate types - if (uniform.isArray()) - { - encoder->exitAggregateType(); - } - } -} - -bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog, const Caps &caps) -{ - ASSERT(IsSampler(uniform.type)); - ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); - - if (uniform.vsRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, - &mUsedVertexSamplerRange)) - { - infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", - mSamplersVS.size()); - return false; - } - - unsigned int maxVertexVectors = mProgram->getRenderer()->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; - if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) - { - infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", - caps.maxVertexUniformVectors); - return false; - } - } - - if (uniform.psRegisterIndex != GL_INVALID_INDEX) - { - if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, - &mUsedPixelSamplerRange)) - { - infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", - mSamplersPS.size()); - return false; - } - - unsigned int maxFragmentVectors = mProgram->getRenderer()->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; - if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) - { - infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", - caps.maxFragmentUniformVectors); - return false; - } - } - - return true; -} - -bool ProgramBinary::indexUniforms(InfoLog &infoLog, const Caps &caps) -{ - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - const LinkedUniform &uniform = *mUniforms[uniformIndex]; - - if (IsSampler(uniform.type)) - { - if (!indexSamplerUniform(uniform, infoLog, caps)) - { - return false; - } - } - - for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) - { - mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); - } - } - - return true; -} - -bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex, - GLenum samplerType, - unsigned int samplerCount, - std::vector &outSamplers, - GLuint *outUsedRange) -{ - unsigned int samplerIndex = startSamplerIndex; - - do - { - if (samplerIndex < outSamplers.size()) - { - Sampler& sampler = outSamplers[samplerIndex]; - sampler.active = true; - sampler.textureType = GetTextureType(samplerType); - sampler.logicalTextureUnit = 0; - *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); - } - else - { - return false; - } - - samplerIndex++; - } while (samplerIndex < startSamplerIndex + samplerCount); - - return true; -} - -bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock) -{ - const char* blockName = vertexInterfaceBlock.name.c_str(); - - // validate blocks for the same member types - if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size()) - { - infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName); - return false; - } - - if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize) - { - infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName); - return false; - } - - if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout) - { - infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName); - return false; - } - - const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size(); - for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++) - { - const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex]; - const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex]; - - if (vertexMember.name != fragmentMember.name) - { - infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')", - blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str()); - return false; - } - - std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'"; - if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember)) - { - return false; - } - } - - return true; -} - -bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps) -{ - const std::vector &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks(); - const std::vector &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks(); - - // Check that interface blocks defined in the vertex and fragment shaders are identical - typedef std::map UniformBlockMap; - UniformBlockMap linkedUniformBlocks; - - for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex]; - linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock; - } - - for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex]; - UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name); - if (entry != linkedUniformBlocks.end()) - { - const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second; - if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock)) - { - return false; - } - } - } - - for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex]; - - // Note: shared and std140 layouts are always considered active - if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) - { - if (!defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps)) - { - return false; - } - } - } - - for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++) - { - const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex]; - - // Note: shared and std140 layouts are always considered active - if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED) - { - if (!defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps)) - { - return false; - } - } - } - - return true; -} - bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, const std::vector &transformFeedbackVaryingNames, GLenum transformFeedbackBufferMode, @@ -2253,142 +907,6 @@ bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, cons return true; } -template -void ProgramBinary::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, - bool inRowMajorLayout) -{ - for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) - { - const VarT &field = fields[uniformIndex]; - const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); - - if (field.isStruct()) - { - bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); - - for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) - { - encoder->enterAggregateType(); - - const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); - defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout); - - encoder->exitAggregateType(); - } - } - else - { - bool isRowMajorMatrix = (IsMatrixType(field.type) && inRowMajorLayout); - - sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); - - LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize, - blockIndex, memberInfo); - - // add to uniform list, but not index, since uniform block uniforms have no location - blockUniformIndexes->push_back(mUniforms.size()); - mUniforms.push_back(newUniform); - } - } -} - -bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock, const Caps &caps) -{ - const rx::ShaderD3D* shaderD3D = rx::ShaderD3D::makeShaderD3D(shader.getImplementation()); - - // create uniform block entries if they do not exist - if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) - { - std::vector blockUniformIndexes; - const unsigned int blockIndex = mUniformBlocks.size(); - - // define member uniforms - sh::BlockLayoutEncoder *encoder = NULL; - - if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) - { - encoder = new sh::Std140BlockEncoder; - } - else - { - encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); - } - ASSERT(encoder); - - defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout); - - size_t dataSize = encoder->getBlockSize(); - - // create all the uniform blocks - if (interfaceBlock.arraySize > 0) - { - for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) - { - UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } - } - else - { - UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); - newUniformBlock->memberUniformIndexes = blockUniformIndexes; - mUniformBlocks.push_back(newUniformBlock); - } - } - - if (interfaceBlock.staticUse) - { - // Assign registers to the uniform blocks - const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); - const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); - ASSERT(blockIndex != GL_INVALID_INDEX); - ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); - - unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); - - for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) - { - UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; - ASSERT(uniformBlock->name == interfaceBlock.name); - - if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), - interfaceBlockRegister + uniformBlockElement, caps)) - { - return false; - } - } - } - - return true; -} - -bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps) -{ - if (shader == GL_VERTEX_SHADER) - { - uniformBlock->vsRegisterIndex = registerIndex; - if (registerIndex - mProgram->getRenderer()->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) - { - infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); - return false; - } - } - else if (shader == GL_FRAGMENT_SHADER) - { - uniformBlock->psRegisterIndex = registerIndex; - if (registerIndex - mProgram->getRenderer()->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) - { - infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); - return false; - } - } - else UNREACHABLE(); - - return true; -} - bool ProgramBinary::isValidated() const { return mValidated; @@ -2464,13 +982,13 @@ GLint ProgramBinary::getActiveAttributeMaxLength() const void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const { - ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount() + ASSERT(index < mProgram->getUniforms().size()); // index must be smaller than getActiveUniformCount() if (bufsize > 0) { - std::string string = mUniforms[index]->name; + std::string string = mProgram->getUniforms()[index]->name; - if (mUniforms[index]->isArray()) + if (mProgram->getUniforms()[index]->isArray()) { string += "[0]"; } @@ -2484,27 +1002,27 @@ void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *len } } - *size = mUniforms[index]->elementCount(); + *size = mProgram->getUniforms()[index]->elementCount(); - *type = mUniforms[index]->type; + *type = mProgram->getUniforms()[index]->type; } GLint ProgramBinary::getActiveUniformCount() const { - return mUniforms.size(); + return mProgram->getUniforms().size(); } GLint ProgramBinary::getActiveUniformMaxLength() const { int maxLength = 0; - unsigned int numUniforms = mUniforms.size(); + unsigned int numUniforms = mProgram->getUniforms().size(); for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++) { - if (!mUniforms[uniformIndex]->name.empty()) + if (!mProgram->getUniforms()[uniformIndex]->name.empty()) { - int length = (int)(mUniforms[uniformIndex]->name.length() + 1); - if (mUniforms[uniformIndex]->isArray()) + int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1); + if (mProgram->getUniforms()[uniformIndex]->isArray()) { length += 3; // Counting in "[0]". } @@ -2517,7 +1035,7 @@ GLint ProgramBinary::getActiveUniformMaxLength() const GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const { - const gl::LinkedUniform& uniform = *mUniforms[index]; + const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index]; switch (pname) { @@ -2540,34 +1058,25 @@ GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const bool ProgramBinary::isValidUniformLocation(GLint location) const { - ASSERT(rx::IsIntegerCastSafe(mUniformIndex.size())); - return (location >= 0 && location < static_cast(mUniformIndex.size())); + ASSERT(rx::IsIntegerCastSafe(mProgram->getUniformIndices().size())); + return (location >= 0 && location < static_cast(mProgram->getUniformIndices().size())); } LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const { - ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); - return mUniforms[mUniformIndex[location].index]; + return mProgram->getUniformByLocation(location); } LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const { - for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) - { - if (mUniforms[uniformIndex]->name == name) - { - return mUniforms[uniformIndex]; - } - } - - return NULL; + return mProgram->getUniformByName(name); } void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const { - ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() - const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; if (bufSize > 0) { @@ -2590,9 +1099,9 @@ void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const { - ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount() + ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size()); // index must be smaller than getActiveUniformBlockCount() - const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; switch (pname) { @@ -2625,17 +1134,17 @@ void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pna GLuint ProgramBinary::getActiveUniformBlockCount() const { - return mUniformBlocks.size(); + return mProgram->getUniformBlocks().size(); } GLuint ProgramBinary::getActiveUniformBlockMaxLength() const { unsigned int maxLength = 0; - unsigned int numUniformBlocks = mUniformBlocks.size(); + unsigned int numUniformBlocks = mProgram->getUniformBlocks().size(); for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++) { - const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex]; + const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex]; if (!uniformBlock.name.empty()) { const unsigned int length = uniformBlock.name.length() + 1; @@ -2665,88 +1174,7 @@ void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps) bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps) { - // if any two active samplers in a program are of different types, but refer to the same - // texture image unit, and this is the current program, then ValidateProgram will fail, and - // DrawArrays and DrawElements will issue the INVALID_OPERATION error. - updateSamplerMapping(); - - std::vector textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE); - - for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) - { - if (mSamplersPS[i].active) - { - unsigned int unit = mSamplersPS[i].logicalTextureUnit; - - if (unit >= textureUnitTypes.size()) - { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); - } - - return false; - } - - if (textureUnitTypes[unit] != GL_NONE) - { - if (mSamplersPS[i].textureType != textureUnitTypes[unit]) - { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; - } - } - else - { - textureUnitTypes[unit] = mSamplersPS[i].textureType; - } - } - } - - for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) - { - if (mSamplersVS[i].active) - { - unsigned int unit = mSamplersVS[i].logicalTextureUnit; - - if (unit >= textureUnitTypes.size()) - { - if (infoLog) - { - infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); - } - - return false; - } - - if (textureUnitTypes[unit] != GL_NONE) - { - if (mSamplersVS[i].textureType != textureUnitTypes[unit]) - { - if (infoLog) - { - infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); - } - - return false; - } - } - else - { - textureUnitTypes[unit] = mSamplersVS[i].textureType; - } - } - } - - return true; -} - -ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D) -{ + return mProgram->validateSamplers(infoLog, caps); } struct AttributeSorter @@ -2795,26 +1223,6 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA void ProgramBinary::reset() { - SafeDeleteContainer(mVertexExecutables); - SafeDeleteContainer(mPixelExecutables); - - SafeDelete(mGeometryExecutable); - - mTransformFeedbackBufferMode = GL_NONE; - mTransformFeedbackLinkedVaryings.clear(); - - mSamplersPS.clear(); - mSamplersVS.clear(); - - mUsedVertexSamplerRange = 0; - mUsedPixelSamplerRange = 0; - mUsesPointSize = false; - mShaderVersion = 0; - mDirtySamplerMapping = true; - - SafeDeleteContainer(mUniforms); - SafeDeleteContainer(mUniformBlocks); - mUniformIndex.clear(); mOutputVariables.clear(); mProgram->reset(); diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h index ad470d417b..3142d66c6d 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.h @@ -24,11 +24,6 @@ #include #include -// TODO(jmadill): place this in workarounds library -#define ANGLE_WORKAROUND_ENABLED 1 -#define ANGLE_WORKAROUND_DISABLED 2 -#define ANGLE_MRT_PERF_WORKAROUND ANGLE_WORKAROUND_ENABLED - namespace sh { class HLSLBlockEncoder; @@ -44,7 +39,6 @@ class HLSLBlockEncoder; namespace rx { class ShaderExecutable; -class Renderer; struct TranslatedAttribute; class UniformStorage; class ProgramImpl; @@ -58,6 +52,7 @@ class InfoLog; class AttributeBindings; class Buffer; class Framebuffer; +struct Data; // Struct used for correlating uniforms/elements of uniform arrays to handles struct VariableLocation @@ -91,6 +86,14 @@ struct LinkedVarying unsigned int semanticIndexCount; }; +struct LinkResult +{ + bool linkSuccess; + Error error; + + LinkResult(bool linkSuccess, const Error &error); +}; + // This is the result of linking a program. It is the state that would be passed to ProgramBinary. class ProgramBinary : public RefCountObject { @@ -101,11 +104,6 @@ class ProgramBinary : public RefCountObject rx::ProgramImpl *getImplementation() { return mProgram; } const rx::ProgramImpl *getImplementation() const { return mProgram; } - rx::ShaderExecutable *getPixelExecutableForFramebuffer(const Framebuffer *fbo); - rx::ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector &outputLayout); - rx::ShaderExecutable *getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]); - rx::ShaderExecutable *getGeometryExecutable() const; - GLuint getAttributeLocation(const char *name); int getSemanticIndex(int attributeIndex); @@ -113,8 +111,6 @@ class ProgramBinary : public RefCountObject GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex); GLint getUsedSamplerRange(SamplerType type); bool usesPointSize() const; - bool usesPointSpriteEmulation() const; - bool usesGeometryShader() const; GLint getUniformLocation(std::string name); GLuint getUniformIndex(std::string name); @@ -145,18 +141,17 @@ class ProgramBinary : public RefCountObject void getUniformiv(GLint location, GLint *params); void getUniformuiv(GLint location, GLuint *params); - void dirtyAllUniforms(); - Error applyUniforms(); Error applyUniformBuffers(const std::vector boundBuffers, const Caps &caps); - bool load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length); - bool save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length); + LinkResult load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length); + Error save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length); GLint getLength(); - bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader, - const std::vector& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps); - void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); + LinkResult link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings, + Shader *fragmentShader, Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode); void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveAttributeCount() const; @@ -188,30 +183,23 @@ class ProgramBinary : public RefCountObject void updateSamplerMapping(); unsigned int getSerial() const; - int getShaderVersion() const; void initAttributesByLayout(); void sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const; - const std::vector &getUniforms() const { return mUniforms; } - static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader); + static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); + static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); private: DISALLOW_COPY_AND_ASSIGN(ProgramBinary); - struct Sampler - { - Sampler(); - - bool active; - GLint logicalTextureUnit; - GLenum textureType; - }; - void reset(); bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader); + bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); + bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, + const sh::InterfaceBlock &fragmentInterfaceBlock); static bool linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, @@ -219,102 +207,21 @@ class ProgramBinary : public RefCountObject const sh::ShaderVariable &fragmentVariable, bool validatePrecision); - static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform); static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying); - static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); - bool linkUniforms(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); - void defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister); - void defineUniform(GLenum shader, const sh::ShaderVariable &uniform, const std::string &fullName, sh::HLSLBlockEncoder *encoder); - bool indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog, const Caps &caps); - bool indexUniforms(InfoLog &infoLog, const Caps &caps); - static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, - std::vector &outSamplers, GLuint *outUsedRange); - bool areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock); - bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps); bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector &linkedVaryings, const std::vector &transformFeedbackVaryingNames, GLenum transformFeedbackBufferMode, std::vector *outTransformFeedbackLinkedVaryings, const Caps &caps) const; - template - void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, - sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, - bool inRowMajorLayout); - bool defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock, const Caps &caps); bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); void defineOutputVariables(Shader *fragmentShader); - template - void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); - - template - void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); - - template - void getUniformv(GLint location, T *params, GLenum uniformType); - - class VertexExecutable - { - public: - VertexExecutable(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS], - const GLenum signature[MAX_VERTEX_ATTRIBS], - rx::ShaderExecutable *shaderExecutable); - ~VertexExecutable(); - - bool matchesSignature(const GLenum convertedLayout[MAX_VERTEX_ATTRIBS]) const; - - const VertexFormat *inputs() const { return mInputs; } - const GLenum *signature() const { return mSignature; } - rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } - - private: - VertexFormat mInputs[MAX_VERTEX_ATTRIBS]; - GLenum mSignature[MAX_VERTEX_ATTRIBS]; - rx::ShaderExecutable *mShaderExecutable; - }; - - class PixelExecutable - { - public: - PixelExecutable(const std::vector &outputSignature, rx::ShaderExecutable *shaderExecutable); - ~PixelExecutable(); - - bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } - - const std::vector &outputSignature() const { return mOutputSignature; } - rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } - - private: - std::vector mOutputSignature; - rx::ShaderExecutable *mShaderExecutable; - }; - rx::ProgramImpl *mProgram; - std::vector mVertexExecutables; - std::vector mPixelExecutables; - - rx::ShaderExecutable *mGeometryExecutable; - sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS]; - sh::Attribute mShaderAttributes[MAX_VERTEX_ATTRIBS]; int mSemanticIndex[MAX_VERTEX_ATTRIBS]; int mAttributesByLayout[MAX_VERTEX_ATTRIBS]; - GLenum mTransformFeedbackBufferMode; - std::vector mTransformFeedbackLinkedVaryings; - - std::vector mSamplersPS; - std::vector mSamplersVS; - GLuint mUsedVertexSamplerRange; - GLuint mUsedPixelSamplerRange; - bool mUsesPointSize; - int mShaderVersion; - bool mDirtySamplerMapping; - - std::vector mUniforms; - std::vector mUniformBlocks; - std::vector mUniformIndex; std::map mOutputVariables; bool mValidated; diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp index 9406fce58d..911a389dfa 100644 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.cpp @@ -4,77 +4,86 @@ // found in the LICENSE file. // -// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes -// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer -// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. +// Renderbuffer.cpp: Implements the renderer-agnostic gl::Renderbuffer class, +// GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Texture.h" #include "libGLESv2/formatutils.h" #include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/renderer/RenderbufferImpl.h" #include "common/utilities.h" namespace gl { -unsigned int RenderbufferStorage::mCurrentSerial = 1; - -Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *newStorage) +Renderbuffer::Renderbuffer(rx::RenderbufferImpl *impl, GLuint id) : RefCountObject(id), - mStorage(newStorage) + mRenderbuffer(impl) { - ASSERT(mStorage); + ASSERT(mRenderbuffer); + + mWidth = mRenderbuffer->getWidth(); + mHeight = mRenderbuffer->getHeight(); + mInternalFormat = mRenderbuffer->getInternalFormat(); + mActualFormat = mRenderbuffer->getActualFormat(); + mSamples = mRenderbuffer->getSamples(); } Renderbuffer::~Renderbuffer() { - SafeDelete(mStorage); + SafeDelete(mRenderbuffer); } -void Renderbuffer::setStorage(RenderbufferStorage *newStorage) +Error Renderbuffer::setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) { - ASSERT(newStorage); + Error error = mRenderbuffer->setStorage(width, height, internalformat, samples); + if (error.isError()) + { + return error; + } - SafeDelete(mStorage); - mStorage = newStorage; + mWidth = width; + mHeight = height; + mInternalFormat = internalformat; + mSamples = samples; + mActualFormat = mRenderbuffer->getActualFormat(); + + return Error(GL_NO_ERROR); } -RenderbufferStorage *Renderbuffer::getStorage() +rx::RenderbufferImpl *Renderbuffer::getImplementation() { - ASSERT(mStorage); - return mStorage; + ASSERT(mRenderbuffer); + return mRenderbuffer; } GLsizei Renderbuffer::getWidth() const { - ASSERT(mStorage); - return mStorage->getWidth(); + return mWidth; } GLsizei Renderbuffer::getHeight() const { - ASSERT(mStorage); - return mStorage->getHeight(); + return mHeight; } GLenum Renderbuffer::getInternalFormat() const { - ASSERT(mStorage); - return mStorage->getInternalFormat(); + return mInternalFormat; } GLenum Renderbuffer::getActualFormat() const { - ASSERT(mStorage); - return mStorage->getActualFormat(); + return mActualFormat; } GLsizei Renderbuffer::getSamples() const { - ASSERT(mStorage); - return mStorage->getSamples(); + return mSamples; } GLuint Renderbuffer::getRedSize() const @@ -107,176 +116,4 @@ GLuint Renderbuffer::getStencilSize() const return GetInternalFormatInfo(getActualFormat()).stencilBits; } -RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerials(1)) -{ - mWidth = 0; - mHeight = 0; - mInternalFormat = GL_RGBA4; - mActualFormat = GL_RGBA8_OES; - mSamples = 0; -} - -RenderbufferStorage::~RenderbufferStorage() -{ -} - -rx::RenderTarget *RenderbufferStorage::getRenderTarget() -{ - return NULL; -} - -GLsizei RenderbufferStorage::getWidth() const -{ - return mWidth; -} - -GLsizei RenderbufferStorage::getHeight() const -{ - return mHeight; -} - -GLenum RenderbufferStorage::getInternalFormat() const -{ - return mInternalFormat; -} - -GLenum RenderbufferStorage::getActualFormat() const -{ - return mActualFormat; -} - -GLsizei RenderbufferStorage::getSamples() const -{ - return mSamples; -} - -unsigned int RenderbufferStorage::getSerial() const -{ - return mSerial; -} - -unsigned int RenderbufferStorage::issueSerials(unsigned int count) -{ - unsigned int firstSerial = mCurrentSerial; - mCurrentSerial += count; - return firstSerial; -} - -bool RenderbufferStorage::isTexture() const -{ - return false; -} - -unsigned int RenderbufferStorage::getTextureSerial() const -{ - return -1; -} - -Colorbuffer::Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain) -{ - mRenderTarget = renderer->createRenderTarget(swapChain, false); - - if (mRenderTarget) - { - mWidth = mRenderTarget->getWidth(); - mHeight = mRenderTarget->getHeight(); - mInternalFormat = mRenderTarget->getInternalFormat(); - mActualFormat = mRenderTarget->getActualFormat(); - mSamples = mRenderTarget->getSamples(); - } -} - -Colorbuffer::Colorbuffer(rx::Renderer *renderer, int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL) -{ - mRenderTarget = renderer->createRenderTarget(width, height, format, samples); - - if (mRenderTarget) - { - mWidth = width; - mHeight = height; - mInternalFormat = format; - mActualFormat = mRenderTarget->getActualFormat(); - mSamples = mRenderTarget->getSamples(); - } -} - -Colorbuffer::~Colorbuffer() -{ - if (mRenderTarget) - { - delete mRenderTarget; - } -} - -rx::RenderTarget *Colorbuffer::getRenderTarget() -{ - return mRenderTarget; -} - -DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain) -{ - mDepthStencil = renderer->createRenderTarget(swapChain, true); - if (mDepthStencil) - { - mWidth = mDepthStencil->getWidth(); - mHeight = mDepthStencil->getHeight(); - mInternalFormat = mDepthStencil->getInternalFormat(); - mSamples = mDepthStencil->getSamples(); - mActualFormat = mDepthStencil->getActualFormat(); - } -} - -DepthStencilbuffer::DepthStencilbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) -{ - - mDepthStencil = renderer->createRenderTarget(width, height, GL_DEPTH24_STENCIL8_OES, samples); - - mWidth = mDepthStencil->getWidth(); - mHeight = mDepthStencil->getHeight(); - mInternalFormat = GL_DEPTH24_STENCIL8_OES; - mActualFormat = mDepthStencil->getActualFormat(); - mSamples = mDepthStencil->getSamples(); -} - -DepthStencilbuffer::~DepthStencilbuffer() -{ - if (mDepthStencil) - { - delete mDepthStencil; - } -} - -rx::RenderTarget *DepthStencilbuffer::getRenderTarget() -{ - return mDepthStencil; -} - -Depthbuffer::Depthbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) : DepthStencilbuffer(renderer, width, height, samples) -{ - if (mDepthStencil) - { - mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage - } -} - -Depthbuffer::~Depthbuffer() -{ -} - -Stencilbuffer::Stencilbuffer(rx::Renderer *renderer, int width, int height, GLsizei samples) : DepthStencilbuffer(renderer, width, height, samples) -{ - if (mDepthStencil) - { - mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function - // will expect one of the valid renderbuffer formats for use in - // glRenderbufferStorage - } -} - -Stencilbuffer::~Stencilbuffer() -{ -} - } diff --git a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h index 71bcb0e1f8..e9f12af3ce 100644 --- a/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/Renderbuffer.h @@ -4,30 +4,27 @@ // found in the LICENSE file. // -// Renderbuffer.h: Defines the wrapper class gl::Renderbuffer, as well as the -// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer, -// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer -// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. +// Renderbuffer.h: Defines the renderer-agnostic container class gl::Renderbuffer. +// Implements GL renderbuffer objects and related functionality. +// [OpenGL ES 2.0.24] section 4.4.3 page 108. #ifndef LIBGLESV2_RENDERBUFFER_H_ #define LIBGLESV2_RENDERBUFFER_H_ #include "angle_gl.h" +#include "libGLESv2/Error.h" + #include "common/angleutils.h" #include "common/RefCountObject.h" namespace rx { -class Renderer; -class SwapChain; -class RenderTarget; -class TextureStorage; +class RenderbufferImpl; } namespace gl { -class RenderbufferStorage; class FramebufferAttachment; // A GL renderbuffer object is usually used as a depth or stencil buffer attachment @@ -38,11 +35,12 @@ class FramebufferAttachment; class Renderbuffer : public RefCountObject { public: - Renderbuffer(GLuint id, RenderbufferStorage *newStorage); + Renderbuffer(rx::RenderbufferImpl *impl, GLuint id); virtual ~Renderbuffer(); - void setStorage(RenderbufferStorage *newStorage); - RenderbufferStorage *getStorage(); + Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples); + + rx::RenderbufferImpl *getImplementation(); GLsizei getWidth() const; GLsizei getHeight() const; @@ -57,102 +55,15 @@ class Renderbuffer : public RefCountObject GLuint getStencilSize() const; private: - RenderbufferStorage *mStorage; -}; + DISALLOW_COPY_AND_ASSIGN(Renderbuffer); -// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage -// is called. The specific concrete type depends on whether the internal format is -// colour depth, stencil or packed depth/stencil. -class RenderbufferStorage -{ - public: - RenderbufferStorage(); + rx::RenderbufferImpl *mRenderbuffer; - virtual ~RenderbufferStorage() = 0; - - virtual rx::RenderTarget *getRenderTarget(); - - virtual GLsizei getWidth() const; - virtual GLsizei getHeight() const; - virtual GLenum getInternalFormat() const; - virtual GLenum getActualFormat() const; - virtual GLsizei getSamples() const; - - virtual unsigned int getSerial() const; - - virtual bool isTexture() const; - virtual unsigned int getTextureSerial() const; - - static unsigned int issueSerials(unsigned int count); - - protected: GLsizei mWidth; GLsizei mHeight; GLenum mInternalFormat; GLenum mActualFormat; GLsizei mSamples; - - private: - DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage); - - const unsigned int mSerial; - - static unsigned int mCurrentSerial; -}; - -class Colorbuffer : public RenderbufferStorage -{ - public: - Colorbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain); - Colorbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLenum format, GLsizei samples); - - virtual ~Colorbuffer(); - - virtual rx::RenderTarget *getRenderTarget(); - - private: - DISALLOW_COPY_AND_ASSIGN(Colorbuffer); - - rx::RenderTarget *mRenderTarget; -}; - -class DepthStencilbuffer : public RenderbufferStorage -{ - public: - DepthStencilbuffer(rx::Renderer *renderer, rx::SwapChain *swapChain); - DepthStencilbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples); - - ~DepthStencilbuffer(); - - virtual rx::RenderTarget *getRenderTarget(); - - protected: - rx::RenderTarget *mDepthStencil; - - private: - DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer); -}; - -class Depthbuffer : public DepthStencilbuffer -{ - public: - Depthbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples); - - virtual ~Depthbuffer(); - - private: - DISALLOW_COPY_AND_ASSIGN(Depthbuffer); -}; - -class Stencilbuffer : public DepthStencilbuffer -{ - public: - Stencilbuffer(rx::Renderer *renderer, GLsizei width, GLsizei height, GLsizei samples); - - virtual ~Stencilbuffer(); - - private: - DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); }; } diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp index 9121de1750..38d53cad81 100644 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.cpp @@ -21,9 +21,9 @@ namespace gl { ResourceManager::ResourceManager(rx::Renderer *renderer) + : mRenderer(renderer), + mRefCount(1) { - mRefCount = 1; - mRenderer = renderer; } ResourceManager::~ResourceManager() @@ -88,13 +88,13 @@ GLuint ResourceManager::createBuffer() } // Returns an unused shader/program name -GLuint ResourceManager::createShader(GLenum type) +GLuint ResourceManager::createShader(const gl::Data &data, GLenum type) { GLuint handle = mProgramShaderHandleAllocator.allocate(); if (type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER) { - mShaderMap[handle] = new Shader(this, mRenderer->createShader(type), type, handle); + mShaderMap[handle] = new Shader(this, mRenderer->createShader(data, type), type, handle); } else UNREACHABLE(); @@ -146,7 +146,7 @@ GLuint ResourceManager::createFenceSync() { GLuint handle = mFenceSyncHandleAllocator.allocate(); - FenceSync *fenceSync = new FenceSync(mRenderer, handle); + FenceSync *fenceSync = new FenceSync(mRenderer->createFenceSync(), handle); fenceSync->addRef(); mFenceSyncMap[handle] = fenceSync; @@ -295,9 +295,9 @@ Texture *ResourceManager::getTexture(unsigned int handle) } } -Program *ResourceManager::getProgram(unsigned int handle) +Program *ResourceManager::getProgram(unsigned int handle) const { - ProgramMap::iterator program = mProgramMap.find(handle); + ProgramMap::const_iterator program = mProgramMap.find(handle); if (program == mProgramMap.end()) { @@ -403,7 +403,7 @@ void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer) { if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) { - Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(mRenderer, 0, 0, GL_RGBA4, 0)); + Renderbuffer *renderbufferObject = new Renderbuffer(mRenderer->createRenderbuffer(), renderbuffer); mRenderbufferMap[renderbuffer] = renderbufferObject; renderbufferObject->addRef(); } diff --git a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h index 7d53bd4854..acad29b51d 100644 --- a/src/3rdparty/angle/src/libGLESv2/ResourceManager.h +++ b/src/3rdparty/angle/src/libGLESv2/ResourceManager.h @@ -32,6 +32,7 @@ class Texture; class Renderbuffer; class Sampler; class FenceSync; +struct Data; class ResourceManager { @@ -43,7 +44,7 @@ class ResourceManager void release(); GLuint createBuffer(); - GLuint createShader(GLenum type); + GLuint createShader(const gl::Data &data, GLenum type); GLuint createProgram(); GLuint createTexture(); GLuint createRenderbuffer(); @@ -60,7 +61,7 @@ class ResourceManager Buffer *getBuffer(GLuint handle); Shader *getShader(GLuint handle); - Program *getProgram(GLuint handle); + Program *getProgram(GLuint handle) const; Texture *getTexture(GLuint handle); Renderbuffer *getRenderbuffer(GLuint handle); Sampler *getSampler(GLuint handle); @@ -78,8 +79,8 @@ class ResourceManager private: DISALLOW_COPY_AND_ASSIGN(ResourceManager); - std::size_t mRefCount; rx::Renderer *mRenderer; + std::size_t mRefCount; typedef std::unordered_map BufferMap; BufferMap mBufferMap; diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.cpp b/src/3rdparty/angle/src/libGLESv2/Shader.cpp index 4cf5251ff9..1cc17a0501 100644 --- a/src/3rdparty/angle/src/libGLESv2/Shader.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Shader.cpp @@ -118,9 +118,15 @@ void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) getSourceImpl(mShader->getTranslatedSource(), bufSize, length, buffer); } -void Shader::compile() +void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const { - mCompiled = mShader->compile(mSource); + std::string debugInfo(mShader->getDebugInfo()); + getSourceImpl(debugInfo, bufSize, length, buffer); +} + +void Shader::compile(const gl::Data &data) +{ + mCompiled = mShader->compile(data, mSource); } void Shader::addRef() diff --git a/src/3rdparty/angle/src/libGLESv2/Shader.h b/src/3rdparty/angle/src/libGLESv2/Shader.h index 7ba3bd165c..904217dab8 100644 --- a/src/3rdparty/angle/src/libGLESv2/Shader.h +++ b/src/3rdparty/angle/src/libGLESv2/Shader.h @@ -31,6 +31,7 @@ class ShaderImpl; namespace gl { class ResourceManager; +struct Data; struct PackedVarying : public sh::Varying { @@ -73,8 +74,9 @@ class Shader void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; int getTranslatedSourceLength() const; void getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const; + void getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const; - void compile(); + void compile(const gl::Data &data); bool isCompiled() const { return mCompiled; } void addRef(); diff --git a/src/3rdparty/angle/src/libGLESv2/State.cpp b/src/3rdparty/angle/src/libGLESv2/State.cpp index 3c03b90e56..b5b62f5848 100644 --- a/src/3rdparty/angle/src/libGLESv2/State.cpp +++ b/src/3rdparty/angle/src/libGLESv2/State.cpp @@ -10,18 +10,20 @@ #include "libGLESv2/Context.h" #include "libGLESv2/Caps.h" -#include "libGLESv2/VertexArray.h" -#include "libGLESv2/Query.h" #include "libGLESv2/Framebuffer.h" #include "libGLESv2/FramebufferAttachment.h" -#include "libGLESv2/renderer/RenderTarget.h" +#include "libGLESv2/Query.h" +#include "libGLESv2/VertexArray.h" #include "libGLESv2/formatutils.h" +#include "libGLESv2/renderer/RenderTarget.h" namespace gl { State::State() { + mMaxDrawBuffers = 0; + mMaxCombinedTextureImageUnits = 0; } State::~State() @@ -31,7 +33,8 @@ State::~State() void State::initialize(const Caps& caps, GLuint clientVersion) { - mContext = NULL; + mMaxDrawBuffers = caps.maxDrawBuffers; + mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; setClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -111,11 +114,15 @@ void State::initialize(const Caps& caps, GLuint clientVersion) mActiveSampler = 0; const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) + mVertexAttribCurrentValues.resize(caps.maxVertexAttributes); + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex) { mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); } + mUniformBuffers.resize(caps.maxCombinedUniformBlocks); + mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes); + mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits); mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits); if (clientVersion >= 3) @@ -153,12 +160,6 @@ void State::reset() mSamplers[samplerIdx].set(NULL); } - const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++) - { - mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues); - } - mArrayBuffer.set(NULL); mRenderbuffer.set(NULL); @@ -170,15 +171,15 @@ void State::reset() } mGenericUniformBuffer.set(NULL); - for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++) + mGenericTransformFeedbackBuffer.set(NULL); + for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr) { - mUniformBuffers[i].set(NULL); + bufItr->set(NULL); } - mGenericTransformFeedbackBuffer.set(NULL); - for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr) { - mTransformFeedbackBuffers[i].set(NULL); + bufItr->set(NULL); } mCopyReadBuffer.set(NULL); @@ -485,7 +486,7 @@ void State::setSampleCoverageParams(GLclampf value, bool invert) mSampleCoverageInvert = invert; } -void State::getSampleCoverageParams(GLclampf *value, bool *invert) +void State::getSampleCoverageParams(GLclampf *value, bool *invert) const { ASSERT(value != NULL && invert != NULL); @@ -612,14 +613,7 @@ void State::setSamplerTexture(GLenum type, Texture *texture) Texture *State::getSamplerTexture(unsigned int sampler, GLenum type) const { - const BindingPointer& binding = mSamplerTextures.at(type)[sampler]; - - if (binding.id() == 0) // Special case: 0 refers to default textures held by Context - { - return NULL; - } - - return binding.get(); + return mSamplerTextures.at(type)[sampler].get(); } GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const @@ -627,7 +621,7 @@ GLuint State::getSamplerTextureId(unsigned int sampler, GLenum type) const return mSamplerTextures.at(type)[sampler].id(); } -void State::detachTexture(GLuint texture) +void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) { // Textures have a detach method on State rather than a simple // removeBinding, because the zero/null texture objects are managed @@ -640,13 +634,15 @@ void State::detachTexture(GLuint texture) for (TextureBindingMap::iterator bindingVec = mSamplerTextures.begin(); bindingVec != mSamplerTextures.end(); bindingVec++) { + GLenum textureType = bindingVec->first; TextureBindingVector &textureVector = bindingVec->second; for (size_t textureIdx = 0; textureIdx < textureVector.size(); textureIdx++) { BindingPointer &binding = textureVector[textureIdx]; if (binding.id() == texture) { - binding.set(NULL); + // Zero textures are the "default" textures instead of NULL + binding.set(zeroTextures.at(textureType).get()); } } } @@ -667,6 +663,19 @@ void State::detachTexture(GLuint texture) } } +void State::initializeZeroTextures(const TextureMap &zeroTextures) +{ + for (TextureMap::const_iterator i = zeroTextures.begin(); i != zeroTextures.end(); i++) + { + TextureBindingVector &samplerTextureArray = mSamplerTextures[i->first]; + + for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) + { + samplerTextureArray[textureUnit].set(i->second.get()); + } + } +} + void State::setSamplerBinding(GLuint textureUnit, Sampler *sampler) { mSamplers[textureUnit].set(sampler); @@ -947,14 +956,14 @@ void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintpt GLuint State::getIndexedUniformBufferId(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + ASSERT(static_cast(index) < mUniformBuffers.size()); return mUniformBuffers[index].id(); } Buffer *State::getIndexedUniformBuffer(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); + ASSERT(static_cast(index) < mUniformBuffers.size()); return mUniformBuffers[index].get(); } @@ -971,25 +980,30 @@ void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffe GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].id(); } Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].get(); } GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const { - ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + ASSERT(static_cast(index) < mTransformFeedbackBuffers.size()); return mTransformFeedbackBuffers[index].getOffset(); } +size_t State::getTransformFeedbackBufferIndexRange() const +{ + return mTransformFeedbackBuffers.size(); +} + void State::setCopyReadBufferBinding(Buffer *buffer) { mCopyReadBuffer.set(buffer); @@ -1033,19 +1047,19 @@ void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled) void State::setVertexAttribf(GLuint index, const GLfloat values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setFloatValues(values); } void State::setVertexAttribu(GLuint index, const GLuint values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setUnsignedIntValues(values); } void State::setVertexAttribi(GLuint index, const GLint values[4]) { - ASSERT(index < gl::MAX_VERTEX_ATTRIBS); + ASSERT(static_cast(index) < mVertexAttribCurrentValues.size()); mVertexAttribCurrentValues[index].setIntValues(values); } @@ -1062,15 +1076,10 @@ const VertexAttribute &State::getVertexAttribState(unsigned int attribNum) const const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const { - ASSERT(attribNum < MAX_VERTEX_ATTRIBS); + ASSERT(static_cast(attribNum) < mVertexAttribCurrentValues.size()); return mVertexAttribCurrentValues[attribNum]; } -const VertexAttribCurrentValueData *State::getVertexAttribCurrentValues() const -{ - return mVertexAttribCurrentValues; -} - const void *State::getVertexAttribPointer(unsigned int attribNum) const { return getVertexArray()->getVertexAttribute(attribNum).pointer; @@ -1180,12 +1189,12 @@ void State::getFloatv(GLenum pname, GLfloat *params) } } -void State::getIntegerv(GLenum pname, GLint *params) +void State::getIntegerv(const gl::Data &data, GLenum pname, GLint *params) { if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT) { unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT); - ASSERT(colorAttachment < mContext->getCaps().maxDrawBuffers); + ASSERT(colorAttachment < mMaxDrawBuffers); Framebuffer *framebuffer = mDrawFramebuffer; *params = framebuffer->getDrawBufferState(colorAttachment); return; @@ -1238,12 +1247,12 @@ void State::getIntegerv(GLenum pname, GLint *params) case GL_SAMPLES: { gl::Framebuffer *framebuffer = mDrawFramebuffer; - if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->completeness(data) == GL_FRAMEBUFFER_COMPLETE) { switch (pname) { case GL_SAMPLE_BUFFERS: - if (framebuffer->getSamples() != 0) + if (framebuffer->getSamples(data) != 0) { *params = 1; } @@ -1253,7 +1262,7 @@ void State::getIntegerv(GLenum pname, GLint *params) } break; case GL_SAMPLES: - *params = framebuffer->getSamples(); + *params = framebuffer->getSamples(data); break; } } @@ -1332,19 +1341,19 @@ void State::getIntegerv(GLenum pname, GLint *params) } break; case GL_TEXTURE_BINDING_2D: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_2D)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_CUBE_MAP: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_CUBE_MAP)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_3D: - ASSERT(mActiveSampler getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_3D)[mActiveSampler].id(); break; case GL_TEXTURE_BINDING_2D_ARRAY: - ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits); + ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits); *params = mSamplerTextures.at(GL_TEXTURE_2D_ARRAY)[mActiveSampler].id(); break; case GL_UNIFORM_BUFFER_BINDING: @@ -1376,13 +1385,13 @@ bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data) switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].id(); } break; case GL_UNIFORM_BUFFER_BINDING: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].id(); } @@ -1399,25 +1408,25 @@ bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data) switch (target) { case GL_TRANSFORM_FEEDBACK_BUFFER_START: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].getOffset(); } break; case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: - if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS) + if (static_cast(index) < mTransformFeedbackBuffers.size()) { *data = mTransformFeedbackBuffers[index].getSize(); } break; case GL_UNIFORM_BUFFER_START: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].getOffset(); } break; case GL_UNIFORM_BUFFER_SIZE: - if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS) + if (static_cast(index) < mUniformBuffers.size()) { *data = mUniformBuffers[index].getSize(); } @@ -1433,9 +1442,9 @@ bool State::hasMappedBuffer(GLenum target) const { if (target == GL_ARRAY_BUFFER) { - for (unsigned int attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++) + for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++) { - const gl::VertexAttribute &vertexAttrib = getVertexAttribState(attribIndex); + const gl::VertexAttribute &vertexAttrib = getVertexAttribState(static_cast(attribIndex)); gl::Buffer *boundBuffer = vertexAttrib.buffer.get(); if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped()) { diff --git a/src/3rdparty/angle/src/libGLESv2/State.h b/src/3rdparty/angle/src/libGLESv2/State.h index 5f0433136c..c3e6106bd8 100644 --- a/src/3rdparty/angle/src/libGLESv2/State.h +++ b/src/3rdparty/angle/src/libGLESv2/State.h @@ -25,6 +25,9 @@ class Query; class VertexArray; class Context; struct Caps; +struct Data; + +typedef std::map< GLenum, BindingPointer > TextureMap; class State { @@ -35,8 +38,6 @@ class State void initialize(const Caps& caps, GLuint clientVersion); void reset(); - void setContext(Context *context) { mContext = context; } - // State chunk getters const RasterizerState &getRasterizerState() const; const BlendState &getBlendState() const; @@ -100,7 +101,7 @@ class State bool isSampleCoverageEnabled() const; void setSampleCoverage(bool enabled); void setSampleCoverageParams(GLclampf value, bool invert); - void getSampleCoverageParams(GLclampf *value, bool *invert); + void getSampleCoverageParams(GLclampf *value, bool *invert) const; // Scissor test state toggle & query bool isScissorTestEnabled() const; @@ -133,7 +134,8 @@ class State void setSamplerTexture(GLenum type, Texture *texture); Texture *getSamplerTexture(unsigned int sampler, GLenum type) const; GLuint getSamplerTextureId(unsigned int sampler, GLenum type) const; - void detachTexture(GLuint texture); + void detachTexture(const TextureMap &zeroTextures, GLuint texture); + void initializeZeroTextures(const TextureMap &zeroTextures); // Sampler object binding manipulation void setSamplerBinding(GLuint textureUnit, Sampler *sampler); @@ -199,6 +201,7 @@ class State GLuint getIndexedTransformFeedbackBufferId(GLuint index) const; Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const; GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const; + size_t getTransformFeedbackBufferIndexRange() const; // GL_COPY_[READ/WRITE]_BUFFER void setCopyReadBufferBinding(Buffer *buffer); @@ -220,7 +223,6 @@ class State bool normalized, bool pureInteger, GLsizei stride, const void *pointer); const VertexAttribute &getVertexAttribState(unsigned int attribNum) const; const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const; - const VertexAttribCurrentValueData *getVertexAttribCurrentValues() const; const void *getVertexAttribPointer(unsigned int attribNum) const; // Pixel pack state manipulation @@ -238,7 +240,7 @@ class State // State query functions void getBooleanv(GLenum pname, GLboolean *params); void getFloatv(GLenum pname, GLfloat *params); - void getIntegerv(GLenum pname, GLint *params); + void getIntegerv(const gl::Data &data, GLenum pname, GLint *params); bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data); bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data); @@ -247,7 +249,9 @@ class State private: DISALLOW_COPY_AND_ASSIGN(State); - Context *mContext; + // Cached values from Context's caps + GLuint mMaxDrawBuffers; + GLuint mMaxCombinedTextureImageUnits; ColorF mColorClearValue; GLclampf mDepthClearValue; @@ -283,7 +287,8 @@ class State GLuint mCurrentProgramId; BindingPointer mCurrentProgramBinary; - VertexAttribCurrentValueData mVertexAttribCurrentValues[MAX_VERTEX_ATTRIBS]; // From glVertexAttrib + typedef std::vector VertexAttribVector; + VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib VertexArray *mVertexArray; // Texture and sampler bindings @@ -300,11 +305,12 @@ class State ActiveQueryMap mActiveQueries; BindingPointer mGenericUniformBuffer; - OffsetBindingPointer mUniformBuffers[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS]; + typedef std::vector< OffsetBindingPointer > BufferVector; + BufferVector mUniformBuffers; BindingPointer mTransformFeedback; BindingPointer mGenericTransformFeedbackBuffer; - OffsetBindingPointer mTransformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + BufferVector mTransformFeedbackBuffers; BindingPointer mCopyReadBuffer; BindingPointer mCopyWriteBuffer; diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.cpp b/src/3rdparty/angle/src/libGLESv2/Texture.cpp index 3ec492de07..cd4fc4e32a 100644 --- a/src/3rdparty/angle/src/libGLESv2/Texture.cpp +++ b/src/3rdparty/angle/src/libGLESv2/Texture.cpp @@ -47,11 +47,14 @@ bool IsPointSampled(const gl::SamplerState &samplerState) return (samplerState.magFilter == GL_NEAREST && (samplerState.minFilter == GL_NEAREST || samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST)); } +unsigned int Texture::mCurrentTextureSerial = 1; + Texture::Texture(rx::TextureImpl *impl, GLuint id, GLenum target) : RefCountObject(id), mTexture(impl), + mTextureSerial(issueTextureSerial()), mUsage(GL_NONE), - mImmutable(false), + mImmutableLevelCount(0), mTarget(target) { } @@ -72,16 +75,6 @@ void Texture::setUsage(GLenum usage) getImplementation()->setUsage(usage); } -void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler) -{ - *sampler = mSamplerState; - - // Offset the effective base level by the texture storage's top level - rx::TextureStorage *texture = getNativeTexture(); - int topLevel = texture ? texture->getTopLevel() : 0; - sampler->baseLevel = topLevel + mSamplerState.baseLevel; -} - GLenum Texture::getUsage() const { return mUsage; @@ -138,35 +131,35 @@ GLenum Texture::getActualFormat(const ImageIndex &index) const return image->getActualFormat(); } -rx::TextureStorage *Texture::getNativeTexture() +Error Texture::generateMipmaps() { - return getImplementation()->getNativeTexture(); + return getImplementation()->generateMipmaps(); } -void Texture::generateMipmaps() +Error Texture::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) { - getImplementation()->generateMipmaps(); + return mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); } -void Texture::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +unsigned int Texture::getTextureSerial() const { - getImplementation()->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source); + return mTextureSerial; } -unsigned int Texture::getTextureSerial() +unsigned int Texture::issueTextureSerial() { - rx::TextureStorage *texture = getNativeTexture(); - return texture ? texture->getTextureSerial() : 0; + return mCurrentTextureSerial++; } bool Texture::isImmutable() const { - return mImmutable; + return (mImmutableLevelCount > 0); } int Texture::immutableLevelCount() { - return (mImmutable ? getNativeTexture()->getLevelCount() : 0); + return mImmutableLevelCount; } int Texture::mipLevels() const @@ -226,11 +219,11 @@ GLenum Texture2D::getActualFormat(GLint level) const return GL_NONE; } -void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { releaseTexImage(); - mTexture->setImage(GL_TEXTURE_2D, level, width, height, 1, internalFormat, format, type, unpack, pixels); + return mTexture->setImage(GL_TEXTURE_2D, level, width, height, 1, internalFormat, format, type, unpack, pixels); } void Texture2D::bindTexImage(egl::Surface *surface) @@ -254,35 +247,44 @@ void Texture2D::releaseTexImage() } } -void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) +Error Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, + const PixelUnpackState &unpack, const void *pixels) { releaseTexImage(); - mTexture->setCompressedImage(GL_TEXTURE_2D, level, format, width, height, 1, imageSize, pixels); + return mTexture->setCompressedImage(GL_TEXTURE_2D, level, format, width, height, 1, imageSize, unpack, pixels); } -void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImage(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); + return mTexture->subImage(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); } -void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) +Error Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, + GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImageCompressed(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels); + return mTexture->subImageCompressed(GL_TEXTURE_2D, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels); } -void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +Error Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, + Framebuffer *source) { releaseTexImage(); - mTexture->copyImage(GL_TEXTURE_2D, level, format, x, y, width, height, source); + return mTexture->copyImage(GL_TEXTURE_2D, level, format, x, y, width, height, source); } -void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +Error Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - mImmutable = true; + Error error = mTexture->storage(GL_TEXTURE_2D, levels, internalformat, width, height, 1); + if (error.isError()) + { + return error; + } - mTexture->storage(GL_TEXTURE_2D, levels, internalformat, width, height, 1); + mImmutableLevelCount = levels; + + return Error(GL_NO_ERROR); } // Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85. @@ -359,11 +361,11 @@ bool Texture2D::isDepth(GLint level) const return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void Texture2D::generateMipmaps() +Error Texture2D::generateMipmaps() { releaseTexImage(); - mTexture->generateMipmaps(); + return mTexture->generateMipmaps(); } // Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -467,49 +469,27 @@ GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const return GL_NONE; } -void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error TextureCubeMap::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, width, height, 1, internalFormat, format, type, unpack, pixels); + return mTexture->setImage(target, level, width, height, 1, internalFormat, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, width, height, 1, internalFormat, format, type, unpack, pixels); + return mTexture->setCompressedImage(target, level, format, width, height, 1, imageSize, unpack, pixels); } -void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, width, height, 1, internalFormat, format, type, unpack, pixels); + return mTexture->subImage(target, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); } -void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, width, height, 1, internalFormat, format, type, unpack, pixels); -} - -void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - mTexture->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, width, height, 1, internalFormat, format, type, unpack, pixels); -} - -void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - mTexture->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, width, height, 1, internalFormat, format, type, unpack, pixels); -} - -void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels) -{ - mTexture->setCompressedImage(target, level, format, width, height, 1, imageSize, pixels); -} - -void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) -{ - mTexture->subImage(target, level, xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels); -} - -void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels) -{ - mTexture->subImageCompressed(target, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels); + return mTexture->subImageCompressed(target, level, xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels); } // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -549,16 +529,23 @@ bool TextureCubeMap::isDepth(GLenum target, GLint level) const return GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0; } -void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) +Error TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, + GLsizei width, GLsizei height, Framebuffer *source) { - mTexture->copyImage(target, level, format, x, y, width, height, source); + return mTexture->copyImage(target, level, format, x, y, width, height, source); } -void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) +Error TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size) { - mImmutable = true; + Error error = mTexture->storage(GL_TEXTURE_CUBE_MAP, levels, internalformat, size, size, 1); + if (error.isError()) + { + return error; + } - mTexture->storage(GL_TEXTURE_CUBE_MAP, levels, internalformat, size, size, 1); + mImmutableLevelCount = levels; + + return Error(GL_NO_ERROR); } // Tests for texture sampling completeness @@ -734,31 +721,40 @@ bool Texture3D::isDepth(GLint level) const return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_3D, level, width, height, depth, internalFormat, format, type, unpack, pixels); + return mTexture->setImage(GL_TEXTURE_3D, level, width, height, depth, internalFormat, format, type, unpack, pixels); } -void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +Error Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setCompressedImage(GL_TEXTURE_3D, level, format, width, height, depth, imageSize, pixels); + return mTexture->setCompressedImage(GL_TEXTURE_3D, level, format, width, height, depth, imageSize, unpack, pixels); } -void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImage(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); + return mTexture->subImage(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); } -void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +Error Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImageCompressed(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); + return mTexture->subImageCompressed(GL_TEXTURE_3D, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, unpack, pixels); } -void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +Error Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { - mImmutable = true; + Error error = mTexture->storage(GL_TEXTURE_3D, levels, internalformat, width, height, depth); + if (error.isError()) + { + return error; + } - mTexture->storage(GL_TEXTURE_3D, levels, internalformat, width, height, depth); + mImmutableLevelCount = levels; + + return Error(GL_NO_ERROR); } bool Texture3D::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const @@ -892,31 +888,40 @@ bool Texture2DArray::isDepth(GLint level) const return GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setImage(GL_TEXTURE_2D_ARRAY, level, width, height, depth, internalFormat, format, type, unpack, pixels); + return mTexture->setImage(GL_TEXTURE_2D_ARRAY, level, width, height, depth, internalFormat, format, type, unpack, pixels); } -void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +Error Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->setCompressedImage(GL_TEXTURE_2D_ARRAY, level, format, width, height, depth, imageSize, pixels); + return mTexture->setCompressedImage(GL_TEXTURE_2D_ARRAY, level, format, width, height, depth, imageSize, unpack, pixels); } -void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) +Error Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImage(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); + return mTexture->subImage(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels); } -void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +Error Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels) { - mTexture->subImageCompressed(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels); + return mTexture->subImageCompressed(GL_TEXTURE_2D_ARRAY, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, unpack, pixels); } -void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +Error Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { - mImmutable = true; + Error error = mTexture->storage(GL_TEXTURE_2D_ARRAY, levels, internalformat, width, height, depth); + if (error.isError()) + { + return error; + } - mTexture->storage(GL_TEXTURE_2D_ARRAY, levels, internalformat, width, height, depth); + mImmutableLevelCount = levels; + + return Error(GL_NO_ERROR); } bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const diff --git a/src/3rdparty/angle/src/libGLESv2/Texture.h b/src/3rdparty/angle/src/libGLESv2/Texture.h index ca5686fde3..66d4df8015 100644 --- a/src/3rdparty/angle/src/libGLESv2/Texture.h +++ b/src/3rdparty/angle/src/libGLESv2/Texture.h @@ -14,7 +14,7 @@ #include "common/debug.h" #include "common/RefCountObject.h" #include "libGLESv2/angletypes.h" -#include "libGLESv2/constants.h" +#include "libGLESv2/Constants.h" #include "libGLESv2/renderer/TextureImpl.h" #include "libGLESv2/Caps.h" @@ -52,7 +52,6 @@ class Texture : public RefCountObject const SamplerState &getSamplerState() const { return mSamplerState; } SamplerState &getSamplerState() { return mSamplerState; } - void getSamplerStateWithNativeOffset(SamplerState *sampler); void setUsage(GLenum usage); GLenum getUsage() const; @@ -69,15 +68,16 @@ class Texture : public RefCountObject virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const = 0; - rx::TextureStorage *getNativeTexture(); + virtual Error generateMipmaps(); - virtual void generateMipmaps(); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + virtual Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - unsigned int getTextureSerial(); + // Texture serials provide a unique way of identifying a Texture that isn't a raw pointer. + // "id" is not good enough, as Textures can be deleted, then re-allocated with the same id. + unsigned int getTextureSerial() const; bool isImmutable() const; - int immutableLevelCount(); + GLsizei immutableLevelCount(); rx::TextureImpl *getImplementation() { return mTexture; } const rx::TextureImpl *getImplementation() const { return mTexture; } @@ -86,17 +86,20 @@ class Texture : public RefCountObject protected: int mipLevels() const; + const rx::Image *getBaseLevelImage() const; + static unsigned int issueTextureSerial(); rx::TextureImpl *mTexture; SamplerState mSamplerState; GLenum mUsage; - bool mImmutable; + GLsizei mImmutableLevelCount; GLenum mTarget; - const rx::Image *getBaseLevelImage() const; + const unsigned int mTextureSerial; + static unsigned int mCurrentTextureSerial; private: DISALLOW_COPY_AND_ASSIGN(Texture); @@ -116,18 +119,18 @@ class Texture2D : public Texture bool isCompressed(GLint level) const; bool isDepth(GLint level) const; - void setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); - void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); - void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); + Error setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); - virtual void generateMipmaps(); + virtual Error generateMipmaps(); private: DISALLOW_COPY_AND_ASSIGN(Texture2D); @@ -152,19 +155,12 @@ class TextureCubeMap : public Texture bool isCompressed(GLenum target, GLint level) const; bool isDepth(GLenum target, GLint level) const; - void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - - void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels); - - void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels); - void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); - void storage(GLsizei levels, GLenum internalformat, GLsizei size); + Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source); + Error storage(GLsizei levels, GLenum internalformat, GLsizei size); virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; @@ -195,11 +191,11 @@ class Texture3D : public Texture bool isCompressed(GLint level) const; bool isDepth(GLint level) const; - void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + Error setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; @@ -225,11 +221,11 @@ class Texture2DArray : public Texture bool isCompressed(GLint level) const; bool isDepth(GLint level) const; - void setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - void subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); - void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - void storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + Error setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels); + Error subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const PixelUnpackState &unpack, const void *pixels); + Error storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual bool isSamplerComplete(const SamplerState &samplerState, const TextureCapsMap &textureCaps, const Extensions &extensions, int clientVersion) const; diff --git a/src/3rdparty/angle/src/libGLESv2/VertexArray.h b/src/3rdparty/angle/src/libGLESv2/VertexArray.h index 993ba042cf..a724c0be1c 100644 --- a/src/3rdparty/angle/src/libGLESv2/VertexArray.h +++ b/src/3rdparty/angle/src/libGLESv2/VertexArray.h @@ -14,14 +14,13 @@ #define LIBGLESV2_VERTEXARRAY_H_ #include "common/RefCountObject.h" -#include "libGLESv2/constants.h" +#include "libGLESv2/Constants.h" #include "libGLESv2/VertexAttribute.h" #include namespace rx { -class Renderer; class VertexArrayImpl; } @@ -44,7 +43,7 @@ class VertexArray void setAttributeState(unsigned int attributeIndex, gl::Buffer *boundBuffer, GLint size, GLenum type, bool normalized, bool pureInteger, GLsizei stride, const void *pointer); - const VertexAttribute* getVertexAttributes() const { return mVertexAttributes.data(); } + const VertexAttribute* getVertexAttributes() const { return &mVertexAttributes[0]; } Buffer *getElementArrayBuffer() const { return mElementArrayBuffer.get(); } void setElementArrayBuffer(Buffer *buffer); GLuint getElementArrayBufferId() const { return mElementArrayBuffer.id(); } diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp index bb6425df64..5a0cfc5ad9 100644 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp +++ b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp @@ -9,6 +9,10 @@ #include "libGLESv2/angletypes.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/State.h" +#include "libGLESv2/VertexArray.h" + +#include namespace gl { @@ -148,16 +152,16 @@ VertexFormat::VertexFormat(const VertexAttribute &attrib, GLenum currentValueTyp void VertexFormat::GetInputLayout(VertexFormat *inputLayout, ProgramBinary *programBinary, - const VertexAttribute *attributes, - const gl::VertexAttribCurrentValueData *currentValues) + const State &state) { + const VertexAttribute *vertexAttributes = state.getVertexArray()->getVertexAttributes(); for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) { int semanticIndex = programBinary->getSemanticIndex(attributeIndex); if (semanticIndex != -1) { - inputLayout[semanticIndex] = VertexFormat(attributes[attributeIndex], currentValues[attributeIndex].Type); + inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type); } } } @@ -192,4 +196,15 @@ bool VertexFormat::operator<(const VertexFormat& other) const return mPureInteger < other.mPureInteger; } +bool Box::operator==(const Box &other) const +{ + return (x == other.x && y == other.y && z == other.z && + width == other.width && height == other.height && depth == other.depth); +} + +bool Box::operator!=(const Box &other) const +{ + return !(*this == other); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.h b/src/3rdparty/angle/src/libGLESv2/angletypes.h index 642a6ec266..78fe6b0e26 100644 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.h +++ b/src/3rdparty/angle/src/libGLESv2/angletypes.h @@ -9,13 +9,13 @@ #ifndef LIBGLESV2_ANGLETYPES_H_ #define LIBGLESV2_ANGLETYPES_H_ -#include "libGLESv2/constants.h" +#include "libGLESv2/Constants.h" #include "common/RefCountObject.h" -#include namespace gl { class Buffer; +class State; class ProgramBinary; struct VertexAttribute; struct VertexAttribCurrentValueData; @@ -66,6 +66,8 @@ struct Box Box() : x(0), y(0), z(0), width(0), height(0), depth(0) { } Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in) : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in) { } + bool operator==(const Box &other) const; + bool operator!=(const Box &other) const; }; struct Extents @@ -230,8 +232,7 @@ struct VertexFormat static void GetInputLayout(VertexFormat *inputLayout, ProgramBinary *programBinary, - const VertexAttribute *attributes, - const gl::VertexAttribCurrentValueData *currentValues); + const State& currentValues); bool operator==(const VertexFormat &other) const; bool operator!=(const VertexFormat &other) const; @@ -251,13 +252,6 @@ enum VertexConversionType VERTEX_CONVERT_BOTH = 3 }; -enum D3DWorkaroundType -{ - ANGLE_D3D_WORKAROUND_NONE, - ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION, - ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION -}; - } #endif // LIBGLESV2_ANGLETYPES_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp index 07f5d47473..587950a139 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -34,13 +34,12 @@ #include "libGLESv2/validationES3.h" #include "libGLESv2/queryconversions.h" - extern "C" { // OpenGL ES 2.0 functions -void __stdcall glActiveTexture(GLenum texture) +void GL_APIENTRY glActiveTexture(GLenum texture) { EVENT("(GLenum texture = 0x%X)", texture); @@ -57,7 +56,7 @@ void __stdcall glActiveTexture(GLenum texture) } } -void __stdcall glAttachShader(GLuint program, GLuint shader) +void GL_APIENTRY glAttachShader(GLuint program, GLuint shader) { EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); @@ -103,7 +102,7 @@ void __stdcall glAttachShader(GLuint program, GLuint shader) } } -void __stdcall glBeginQueryEXT(GLenum target, GLuint id) +void GL_APIENTRY glBeginQueryEXT(GLenum target, GLuint id) { EVENT("(GLenum target = 0x%X, GLuint %d)", target, id); @@ -124,7 +123,7 @@ void __stdcall glBeginQueryEXT(GLenum target, GLuint id) } } -void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) +void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name) { EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name); @@ -163,7 +162,7 @@ void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* } } -void __stdcall glBindBuffer(GLenum target, GLuint buffer) +void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer) { EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer); @@ -210,7 +209,7 @@ void __stdcall glBindBuffer(GLenum target, GLuint buffer) } } -void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) +void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer) { EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer); @@ -235,7 +234,7 @@ void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) } } -void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) +void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer) { EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer); @@ -252,7 +251,7 @@ void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) } } -void __stdcall glBindTexture(GLenum target, GLuint texture) +void GL_APIENTRY glBindTexture(GLenum target, GLuint texture) { EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture); @@ -291,7 +290,7 @@ void __stdcall glBindTexture(GLenum target, GLuint texture) } } -void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); @@ -304,12 +303,12 @@ void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp } } -void __stdcall glBlendEquation(GLenum mode) +void GL_APIENTRY glBlendEquation(GLenum mode) { glBlendEquationSeparate(mode, mode); } -void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha); @@ -348,12 +347,12 @@ void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) } } -void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor) +void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) { glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); } -void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)", srcRGB, dstRGB, srcAlpha, dstAlpha); @@ -488,7 +487,7 @@ void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha } } -void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)", target, size, data, usage); @@ -550,7 +549,7 @@ void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, } } -void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) { EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)", target, offset, size, data); @@ -611,7 +610,7 @@ void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, } } -GLenum __stdcall glCheckFramebufferStatus(GLenum target) +GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target) { EVENT("(GLenum target = 0x%X)", target); @@ -626,13 +625,14 @@ GLenum __stdcall glCheckFramebufferStatus(GLenum target) gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); ASSERT(framebuffer); - return framebuffer->completeness(); + + return framebuffer->completeness(context->getData()); } return 0; } -void __stdcall glClear(GLbitfield mask) +void GL_APIENTRY glClear(GLbitfield mask) { EVENT("(GLbitfield mask = 0x%X)", mask); @@ -640,8 +640,9 @@ void __stdcall glClear(GLbitfield mask) if (context) { gl::Framebuffer *framebufferObject = context->getState().getDrawFramebuffer(); + ASSERT(framebufferObject); - if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (framebufferObject->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(gl::Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return; @@ -662,7 +663,7 @@ void __stdcall glClear(GLbitfield mask) } } -void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)", red, green, blue, alpha); @@ -674,7 +675,7 @@ void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclamp } } -void __stdcall glClearDepthf(GLclampf depth) +void GL_APIENTRY glClearDepthf(GLclampf depth) { EVENT("(GLclampf depth = %f)", depth); @@ -685,7 +686,7 @@ void __stdcall glClearDepthf(GLclampf depth) } } -void __stdcall glClearStencil(GLint s) +void GL_APIENTRY glClearStencil(GLint s) { EVENT("(GLint s = %d)", s); @@ -696,7 +697,7 @@ void __stdcall glClearStencil(GLint s) } } -void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)", red, green, blue, alpha); @@ -708,7 +709,7 @@ void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboo } } -void __stdcall glCompileShader(GLuint shader) +void GL_APIENTRY glCompileShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); @@ -731,11 +732,11 @@ void __stdcall glCompileShader(GLuint shader) } } - shaderObject->compile(); + shaderObject->compile(context->getData()); } } -void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, +void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " @@ -771,7 +772,12 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->setCompressedImage(level, internalformat, width, height, imageSize, data); + gl::Error error = texture->setCompressedImage(level, internalformat, width, height, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -783,7 +789,12 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data); + gl::Error error = texture->setCompressedImage(target, level, internalformat, width, height, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -794,7 +805,7 @@ void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum interna } } -void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, +void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " @@ -831,7 +842,12 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); + gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -843,7 +859,12 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); + gl::Error error = texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -854,7 +875,7 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs } } -void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", @@ -884,7 +905,12 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->copyImage(level, internalformat, x, y, width, height, framebuffer); + gl::Error error = texture->copyImage(level, internalformat, x, y, width, height, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -896,7 +922,12 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); + gl::Error error = texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -907,7 +938,7 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma } } -void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", @@ -937,7 +968,12 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); + gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -949,7 +985,12 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); + gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -960,7 +1001,7 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL } } -GLuint __stdcall glCreateProgram(void) +GLuint GL_APIENTRY glCreateProgram(void) { EVENT("()"); @@ -973,7 +1014,7 @@ GLuint __stdcall glCreateProgram(void) return 0; } -GLuint __stdcall glCreateShader(GLenum type) +GLuint GL_APIENTRY glCreateShader(GLenum type) { EVENT("(GLenum type = 0x%X)", type); @@ -995,7 +1036,7 @@ GLuint __stdcall glCreateShader(GLenum type) return 0; } -void __stdcall glCullFace(GLenum mode) +void GL_APIENTRY glCullFace(GLenum mode) { EVENT("(GLenum mode = 0x%X)", mode); @@ -1018,7 +1059,7 @@ void __stdcall glCullFace(GLenum mode) } } -void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) +void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers) { EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers); @@ -1038,7 +1079,7 @@ void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) } } -void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) +void GL_APIENTRY glDeleteFencesNV(GLsizei n, const GLuint* fences) { EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences); @@ -1058,7 +1099,7 @@ void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences) } } -void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers); @@ -1081,7 +1122,7 @@ void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) } } -void __stdcall glDeleteProgram(GLuint program) +void GL_APIENTRY glDeleteProgram(GLuint program) { EVENT("(GLuint program = %d)", program); @@ -1111,7 +1152,7 @@ void __stdcall glDeleteProgram(GLuint program) } } -void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids) +void GL_APIENTRY glDeleteQueriesEXT(GLsizei n, const GLuint *ids) { EVENT("(GLsizei n = %d, const GLuint *ids = 0x%0.8p)", n, ids); @@ -1131,7 +1172,7 @@ void __stdcall glDeleteQueriesEXT(GLsizei n, const GLuint *ids) } } -void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); @@ -1151,7 +1192,7 @@ void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) } } -void __stdcall glDeleteShader(GLuint shader) +void GL_APIENTRY glDeleteShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); @@ -1181,7 +1222,7 @@ void __stdcall glDeleteShader(GLuint shader) } } -void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) +void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures) { EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures); @@ -1204,7 +1245,7 @@ void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) } } -void __stdcall glDepthFunc(GLenum func) +void GL_APIENTRY glDepthFunc(GLenum func) { EVENT("(GLenum func = 0x%X)", func); @@ -1231,7 +1272,7 @@ void __stdcall glDepthFunc(GLenum func) } } -void __stdcall glDepthMask(GLboolean flag) +void GL_APIENTRY glDepthMask(GLboolean flag) { EVENT("(GLboolean flag = %u)", flag); @@ -1242,7 +1283,7 @@ void __stdcall glDepthMask(GLboolean flag) } } -void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) +void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar) { EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar); @@ -1253,7 +1294,7 @@ void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) } } -void __stdcall glDetachShader(GLuint program, GLuint shader) +void GL_APIENTRY glDetachShader(GLuint program, GLuint shader) { EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader); @@ -1302,7 +1343,7 @@ void __stdcall glDetachShader(GLuint program, GLuint shader) } } -void __stdcall glDisable(GLenum cap) +void GL_APIENTRY glDisable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); @@ -1319,7 +1360,7 @@ void __stdcall glDisable(GLenum cap) } } -void __stdcall glDisableVertexAttribArray(GLuint index) +void GL_APIENTRY glDisableVertexAttribArray(GLuint index) { EVENT("(GLuint index = %d)", index); @@ -1336,7 +1377,7 @@ void __stdcall glDisableVertexAttribArray(GLuint index) } } -void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) +void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count); @@ -1357,7 +1398,7 @@ void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) } } -void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +void GL_APIENTRY glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei primcount = %d)", mode, first, count, primcount); @@ -1378,7 +1419,7 @@ void __stdcall glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei coun } } -void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)", mode, count, type, indices); @@ -1401,7 +1442,7 @@ void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLv } } -void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount) +void GL_APIENTRY glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount) { EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei primcount = %d)", mode, count, type, indices, primcount); @@ -1424,7 +1465,7 @@ void __stdcall glDrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum t } } -void __stdcall glEnable(GLenum cap) +void GL_APIENTRY glEnable(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); @@ -1441,7 +1482,7 @@ void __stdcall glEnable(GLenum cap) } } -void __stdcall glEnableVertexAttribArray(GLuint index) +void GL_APIENTRY glEnableVertexAttribArray(GLuint index) { EVENT("(GLuint index = %d)", index); @@ -1458,7 +1499,7 @@ void __stdcall glEnableVertexAttribArray(GLuint index) } } -void __stdcall glEndQueryEXT(GLenum target) +void GL_APIENTRY glEndQueryEXT(GLenum target) { EVENT("GLenum target = 0x%X)", target); @@ -1479,7 +1520,7 @@ void __stdcall glEndQueryEXT(GLenum target) } } -void __stdcall glFinishFenceNV(GLuint fence) +void GL_APIENTRY glFinishFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); @@ -1504,29 +1545,39 @@ void __stdcall glFinishFenceNV(GLuint fence) } } -void __stdcall glFinish(void) +void GL_APIENTRY glFinish(void) { EVENT("()"); gl::Context *context = gl::getNonLostContext(); if (context) { - context->sync(true); + gl::Error error = context->sync(true); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glFlush(void) +void GL_APIENTRY glFlush(void) { EVENT("()"); gl::Context *context = gl::getNonLostContext(); if (context) { - context->sync(false); + gl::Error error = context->sync(false); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, " "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer); @@ -1548,33 +1599,19 @@ void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenu gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); ASSERT(framebuffer); - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + if (renderbuffer != 0) { - unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); - framebuffer->setColorbuffer(colorAttachment, GL_RENDERBUFFER, renderbuffer, 0, 0); + gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + framebuffer->setRenderbufferAttachment(attachment, renderbufferObject); } else { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: - framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); - break; - case GL_STENCIL_ATTACHMENT: - framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); - break; - case GL_DEPTH_STENCIL_ATTACHMENT: - framebuffer->setDepthStencilBuffer(GL_RENDERBUFFER, renderbuffer, 0, 0); - break; - default: - UNREACHABLE(); - break; - } + framebuffer->setNULLAttachment(attachment); } } } -void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, " "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level); @@ -1587,31 +1624,23 @@ void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum t return; } - if (texture == 0) - { - textarget = GL_NONE; - } - gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); + ASSERT(framebuffer); - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + if (texture != 0) { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); - framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, 0); + gl::Texture *textureObj = context->getTexture(texture); + gl::ImageIndex index(textarget, level, gl::ImageIndex::ENTIRE_LEVEL); + framebuffer->setTextureAttachment(attachment, textureObj, index); } else { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level, 0); break; - case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level, 0); break; - case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, 0); break; - } + framebuffer->setNULLAttachment(attachment); } } } -void __stdcall glFrontFace(GLenum mode) +void GL_APIENTRY glFrontFace(GLenum mode) { EVENT("(GLenum mode = 0x%X)", mode); @@ -1631,7 +1660,7 @@ void __stdcall glFrontFace(GLenum mode) } } -void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) +void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers) { EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers); @@ -1651,7 +1680,7 @@ void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) } } -void __stdcall glGenerateMipmap(GLenum target) +void GL_APIENTRY glGenerateMipmap(GLenum target) { EVENT("(GLenum target = 0x%X)", target); @@ -1721,11 +1750,16 @@ void __stdcall glGenerateMipmap(GLenum target) } } - texture->generateMipmaps(); + gl::Error error = texture->generateMipmaps(); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) +void GL_APIENTRY glGenFencesNV(GLsizei n, GLuint* fences) { EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences); @@ -1745,7 +1779,7 @@ void __stdcall glGenFencesNV(GLsizei n, GLuint* fences) } } -void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) +void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers) { EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers); @@ -1765,7 +1799,7 @@ void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) } } -void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenQueriesEXT(GLsizei n, GLuint* ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); @@ -1785,7 +1819,7 @@ void __stdcall glGenQueriesEXT(GLsizei n, GLuint* ids) } } -void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers); @@ -1805,7 +1839,7 @@ void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) } } -void __stdcall glGenTextures(GLsizei n, GLuint* textures) +void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures) { EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures); @@ -1825,7 +1859,7 @@ void __stdcall glGenTextures(GLsizei n, GLuint* textures) } } -void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) +void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) { EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, " "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)", @@ -1866,7 +1900,7 @@ void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, } } -void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, " "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", @@ -1908,7 +1942,7 @@ void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, } } -void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)", program, maxcount, count, shaders); @@ -1942,7 +1976,7 @@ void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* c } } -GLint __stdcall glGetAttribLocation(GLuint program, const GLchar* name) +GLint GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name) { EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name); @@ -1978,7 +2012,7 @@ GLint __stdcall glGetAttribLocation(GLuint program, const GLchar* name) return -1; } -void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) +void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params) { EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params); @@ -2003,7 +2037,7 @@ void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) } } -void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); @@ -2056,7 +2090,7 @@ void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params } } -GLenum __stdcall glGetError(void) +GLenum GL_APIENTRY glGetError(void) { EVENT("()"); @@ -2070,7 +2104,7 @@ GLenum __stdcall glGetError(void) return GL_NO_ERROR; } -void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) +void GL_APIENTRY glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) { EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params); @@ -2094,19 +2128,40 @@ void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) switch (pname) { case GL_FENCE_STATUS_NV: + { + // GL_NV_fence spec: + // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV + // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence. + GLboolean status = GL_TRUE; + if (fenceObject->getStatus() != GL_TRUE) + { + gl::Error error = fenceObject->testFence(&status); + if (error.isError()) + { + context->recordError(error); + return; + } + } + *params = status; + break; + } + case GL_FENCE_CONDITION_NV: - break; + { + *params = fenceObject->getCondition(); + break; + } default: - context->recordError(gl::Error(GL_INVALID_ENUM)); - return; + { + context->recordError(gl::Error(GL_INVALID_ENUM)); + return; + } } - - params[0] = fenceObject->getFencei(pname); } } -void __stdcall glGetFloatv(GLenum pname, GLfloat* params) +void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params) { EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params); @@ -2131,7 +2186,7 @@ void __stdcall glGetFloatv(GLenum pname, GLfloat* params) } } -void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, attachment, pname, params); @@ -2214,6 +2269,7 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac GLuint framebufferHandle = context->getState().getTargetFramebuffer(target)->id(); gl::Framebuffer *framebuffer = context->getFramebuffer(framebufferHandle); + ASSERT(framebuffer); if (framebufferHandle == 0) { @@ -2428,7 +2484,7 @@ void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attac } } -GLenum __stdcall glGetGraphicsResetStatusEXT(void) +GLenum GL_APIENTRY glGetGraphicsResetStatusEXT(void) { EVENT("()"); @@ -2442,7 +2498,7 @@ GLenum __stdcall glGetGraphicsResetStatusEXT(void) return GL_NO_ERROR; } -void __stdcall glGetIntegerv(GLenum pname, GLint* params) +void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params) { EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params); @@ -2468,7 +2524,7 @@ void __stdcall glGetIntegerv(GLenum pname, GLint* params) } } -void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) +void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params) { EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params); @@ -2552,7 +2608,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) } } -void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) { EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", program, bufsize, length, infolog); @@ -2578,7 +2634,7 @@ void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* len } } -void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) +void GL_APIENTRY glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) { EVENT("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", target, pname, params); @@ -2604,7 +2660,7 @@ void __stdcall glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) } } -void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) +void GL_APIENTRY glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) { EVENT("(GLuint id = %d, GLenum pname = 0x%X, GLuint *params = 0x%0.8p)", id, pname, params); @@ -2656,7 +2712,7 @@ void __stdcall glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) } } -void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); @@ -2705,7 +2761,7 @@ void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* } } -void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params); @@ -2748,7 +2804,7 @@ void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) } } -void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) { EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)", shader, bufsize, length, infolog); @@ -2774,7 +2830,7 @@ void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* lengt } } -void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)", shadertype, precisiontype, range, precision); @@ -2821,7 +2877,7 @@ void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontyp } } -void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) { EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", shader, bufsize, length, source); @@ -2847,7 +2903,7 @@ void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length } } -void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +void GL_APIENTRY glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) { EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)", shader, bufsize, length, source); @@ -2869,11 +2925,12 @@ void __stdcall glGetTranslatedShaderSourceANGLE(GLuint shader, GLsizei bufsize, return; } - shaderObject->getTranslatedSource(bufsize, length, source); + // Only returns extra info if ANGLE_GENERATE_SHADER_DEBUG_INFO is defined + shaderObject->getTranslatedSourceWithDebugInfo(bufsize, length, source); } } -const GLubyte* __stdcall glGetString(GLenum name) +const GLubyte* GL_APIENTRY glGetString(GLenum name) { EVENT("(GLenum name = 0x%X)", name); @@ -2919,7 +2976,7 @@ const GLubyte* __stdcall glGetString(GLenum name) } } -void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params); @@ -3051,7 +3108,7 @@ void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) } } -void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); @@ -3098,7 +3155,7 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) context->recordError(gl::Error(GL_INVALID_ENUM)); return; } - *params = texture->immutableLevelCount(); + *params = static_cast(texture->immutableLevelCount()); break; case GL_TEXTURE_USAGE_ANGLE: *params = texture->getUsage(); @@ -3183,7 +3240,7 @@ void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) } } -void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) +void GL_APIENTRY glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params) { EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = 0x%0.8p)", program, location, bufSize, params); @@ -3205,7 +3262,7 @@ void __stdcall glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSiz } } -void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) +void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params) { EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params); @@ -3226,7 +3283,7 @@ void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) } } -void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) +void GL_APIENTRY glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params) { EVENT("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = 0x%0.8p)", program, location, bufSize, params); @@ -3248,7 +3305,7 @@ void __stdcall glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSiz } } -void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params) { EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params); @@ -3269,7 +3326,7 @@ void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) } } -GLint __stdcall glGetUniformLocation(GLuint program, const GLchar* name) +GLint GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name) { EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name); @@ -3310,7 +3367,7 @@ GLint __stdcall glGetUniformLocation(GLuint program, const GLchar* name) return -1; } -void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params); @@ -3344,7 +3401,7 @@ void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) } } -void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); @@ -3380,7 +3437,7 @@ void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) } } -void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) +void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer) { EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer); @@ -3403,7 +3460,7 @@ void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** po } } -void __stdcall glHint(GLenum target, GLenum mode) +void GL_APIENTRY glHint(GLenum target, GLenum mode) { EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode); @@ -3439,7 +3496,7 @@ void __stdcall glHint(GLenum target, GLenum mode) } } -GLboolean __stdcall glIsBuffer(GLuint buffer) +GLboolean GL_APIENTRY glIsBuffer(GLuint buffer) { EVENT("(GLuint buffer = %d)", buffer); @@ -3457,7 +3514,7 @@ GLboolean __stdcall glIsBuffer(GLuint buffer) return GL_FALSE; } -GLboolean __stdcall glIsEnabled(GLenum cap) +GLboolean GL_APIENTRY glIsEnabled(GLenum cap) { EVENT("(GLenum cap = 0x%X)", cap); @@ -3476,7 +3533,7 @@ GLboolean __stdcall glIsEnabled(GLenum cap) return false; } -GLboolean __stdcall glIsFenceNV(GLuint fence) +GLboolean GL_APIENTRY glIsFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); @@ -3496,7 +3553,7 @@ GLboolean __stdcall glIsFenceNV(GLuint fence) return GL_FALSE; } -GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) +GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer) { EVENT("(GLuint framebuffer = %d)", framebuffer); @@ -3514,7 +3571,7 @@ GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) return GL_FALSE; } -GLboolean __stdcall glIsProgram(GLuint program) +GLboolean GL_APIENTRY glIsProgram(GLuint program) { EVENT("(GLuint program = %d)", program); @@ -3532,7 +3589,7 @@ GLboolean __stdcall glIsProgram(GLuint program) return GL_FALSE; } -GLboolean __stdcall glIsQueryEXT(GLuint id) +GLboolean GL_APIENTRY glIsQueryEXT(GLuint id) { EVENT("(GLuint id = %d)", id); @@ -3545,7 +3602,7 @@ GLboolean __stdcall glIsQueryEXT(GLuint id) return GL_FALSE; } -GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) +GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer) { EVENT("(GLuint renderbuffer = %d)", renderbuffer); @@ -3563,7 +3620,7 @@ GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) return GL_FALSE; } -GLboolean __stdcall glIsShader(GLuint shader) +GLboolean GL_APIENTRY glIsShader(GLuint shader) { EVENT("(GLuint shader = %d)", shader); @@ -3581,7 +3638,7 @@ GLboolean __stdcall glIsShader(GLuint shader) return GL_FALSE; } -GLboolean __stdcall glIsTexture(GLuint texture) +GLboolean GL_APIENTRY glIsTexture(GLuint texture) { EVENT("(GLuint texture = %d)", texture); @@ -3599,7 +3656,7 @@ GLboolean __stdcall glIsTexture(GLuint texture) return GL_FALSE; } -void __stdcall glLineWidth(GLfloat width) +void GL_APIENTRY glLineWidth(GLfloat width) { EVENT("(GLfloat width = %f)", width); @@ -3616,7 +3673,7 @@ void __stdcall glLineWidth(GLfloat width) } } -void __stdcall glLinkProgram(GLuint program) +void GL_APIENTRY glLinkProgram(GLuint program) { EVENT("(GLuint program = %d)", program); @@ -3639,11 +3696,16 @@ void __stdcall glLinkProgram(GLuint program) } } - context->linkProgram(program); + gl::Error error = context->linkProgram(program); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glPixelStorei(GLenum pname, GLint param) +void GL_APIENTRY glPixelStorei(GLenum pname, GLint param) { EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param); @@ -3699,7 +3761,7 @@ void __stdcall glPixelStorei(GLenum pname, GLint param) } } -void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) +void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units) { EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units); @@ -3710,7 +3772,7 @@ void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) } } -void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, +void GL_APIENTRY glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data) { @@ -3742,7 +3804,7 @@ void __stdcall glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, } } -void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, +void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, " @@ -3773,7 +3835,7 @@ void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, } } -void __stdcall glReleaseShaderCompiler(void) +void GL_APIENTRY glReleaseShaderCompiler(void) { EVENT("()"); @@ -3785,7 +3847,7 @@ void __stdcall glReleaseShaderCompiler(void) } } -void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", target, samples, internalformat, width, height); @@ -3799,16 +3861,22 @@ void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samp return; } - context->setRenderbufferStorage(width, height, internalformat, samples); + gl::Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); + gl::Error error = renderbuffer->setStorage(width, height, internalformat, samples); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height); } -void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert) { EVENT("(GLclampf value = %f, GLboolean invert = %u)", value, invert); @@ -3820,7 +3888,7 @@ void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) } } -void __stdcall glSetFenceNV(GLuint fence, GLenum condition) +void GL_APIENTRY glSetFenceNV(GLuint fence, GLenum condition) { EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition); @@ -3841,11 +3909,16 @@ void __stdcall glSetFenceNV(GLuint fence, GLenum condition) return; } - fenceObject->setFence(condition); + gl::Error error = fenceObject->setFence(condition); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); @@ -3862,7 +3935,7 @@ void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) } } -void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) { EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, " "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", @@ -3883,7 +3956,7 @@ void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryfor } } -void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) +void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length) { EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)", shader, count, string, length); @@ -3917,12 +3990,12 @@ void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar* const* } } -void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask) { glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); } -void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) { EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask); @@ -3970,12 +4043,12 @@ void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint } } -void __stdcall glStencilMask(GLuint mask) +void GL_APIENTRY glStencilMask(GLuint mask) { glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); } -void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask) { EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask); @@ -4006,12 +4079,12 @@ void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) } } -void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); } -void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)", face, fail, zfail, zpass); @@ -4094,7 +4167,7 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu } } -GLboolean __stdcall glTestFenceNV(GLuint fence) +GLboolean GL_APIENTRY glTestFenceNV(GLuint fence) { EVENT("(GLuint fence = %d)", fence); @@ -4115,13 +4188,21 @@ GLboolean __stdcall glTestFenceNV(GLuint fence) return GL_TRUE; } - return fenceObject->testFence(); + GLboolean result; + gl::Error error = fenceObject->testFence(&result); + if (error.isError()) + { + context->recordError(error); + return GL_TRUE; + } + + return result; } return GL_TRUE; } -void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, +void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, " @@ -4150,51 +4231,38 @@ void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GL case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->setImage(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->setImage(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImagePosX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - } - break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImageNegX(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - } - break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImagePosY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - } - break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImageNegY(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - } - break; case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - { - gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImagePosZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); - } - break; case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->setImageNegZ(level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->setImage(target, level, width, height, internalformat, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; + default: UNREACHABLE(); } } } -void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %f)", target, pname, param); @@ -4238,12 +4306,12 @@ void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) } } -void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { glTexParameterf(target, pname, (GLfloat)*params); } -void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) +void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param); @@ -4287,12 +4355,12 @@ void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) } } -void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params) { glTexParameteri(target, pname, *params); } -void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", target, levels, internalformat, width, height); @@ -4323,14 +4391,24 @@ void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalf case GL_TEXTURE_2D: { gl::Texture2D *texture2d = context->getTexture2D(); - texture2d->storage(levels, internalformat, width, height); + gl::Error error = texture2d->storage(levels, internalformat, width, height); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_CUBE_MAP: { gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - textureCube->storage(levels, internalformat, width); + gl::Error error = textureCube->storage(levels, internalformat, width); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -4341,7 +4419,7 @@ void __stdcall glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalf } } -void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, +void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " @@ -4377,7 +4455,12 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint case GL_TEXTURE_2D: { gl::Texture2D *texture = context->getTexture2D(); - texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -4389,7 +4472,12 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { gl::TextureCubeMap *texture = context->getTextureCubeMap(); - texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -4399,12 +4487,12 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint } } -void __stdcall glUniform1f(GLint location, GLfloat x) +void GL_APIENTRY glUniform1f(GLint location, GLfloat x) { glUniform1fv(location, 1, &x); } -void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); @@ -4421,12 +4509,12 @@ void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) } } -void __stdcall glUniform1i(GLint location, GLint x) +void GL_APIENTRY glUniform1i(GLint location, GLint x) { glUniform1iv(location, 1, &x); } -void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); @@ -4443,14 +4531,14 @@ void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) } } -void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) +void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y) { GLfloat xy[2] = {x, y}; glUniform2fv(location, 1, xy); } -void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); @@ -4467,14 +4555,14 @@ void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) } } -void __stdcall glUniform2i(GLint location, GLint x, GLint y) +void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y) { GLint xy[2] = {x, y}; glUniform2iv(location, 1, xy); } -void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); @@ -4491,14 +4579,14 @@ void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) } } -void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { GLfloat xyz[3] = {x, y, z}; glUniform3fv(location, 1, xyz); } -void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); @@ -4515,14 +4603,14 @@ void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) } } -void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z) { GLint xyz[3] = {x, y, z}; glUniform3iv(location, 1, xyz); } -void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); @@ -4539,14 +4627,14 @@ void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) } } -void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { GLfloat xyzw[4] = {x, y, z, w}; glUniform4fv(location, 1, xyzw); } -void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v); @@ -4563,14 +4651,14 @@ void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) } } -void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { GLint xyzw[4] = {x, y, z, w}; glUniform4iv(location, 1, xyzw); } -void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v) { EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v); @@ -4587,7 +4675,7 @@ void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) } } -void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -4605,7 +4693,7 @@ void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean trans } } -void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -4623,7 +4711,7 @@ void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean trans } } -void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -4641,7 +4729,7 @@ void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean trans } } -void __stdcall glUseProgram(GLuint program) +void GL_APIENTRY glUseProgram(GLuint program) { EVENT("(GLuint program = %d)", program); @@ -4674,7 +4762,7 @@ void __stdcall glUseProgram(GLuint program) } } -void __stdcall glValidateProgram(GLuint program) +void GL_APIENTRY glValidateProgram(GLuint program) { EVENT("(GLuint program = %d)", program); @@ -4701,7 +4789,7 @@ void __stdcall glValidateProgram(GLuint program) } } -void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x) { EVENT("(GLuint index = %d, GLfloat x = %f)", index, x); @@ -4719,7 +4807,7 @@ void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) } } -void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values) { EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); @@ -4737,7 +4825,7 @@ void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) } } -void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y); @@ -4755,7 +4843,7 @@ void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) } } -void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values) { EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); @@ -4773,7 +4861,7 @@ void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) } } -void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z); @@ -4791,7 +4879,7 @@ void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) } } -void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values) { EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); @@ -4809,7 +4897,7 @@ void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) } } -void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w); @@ -4827,7 +4915,7 @@ void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, G } } -void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values) { EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values); @@ -4844,7 +4932,7 @@ void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) } } -void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) +void GL_APIENTRY glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) { EVENT("(GLuint index = %d, GLuint divisor = %d)", index, divisor); @@ -4861,7 +4949,7 @@ void __stdcall glVertexAttribDivisorANGLE(GLuint index, GLuint divisor) } } -void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, " "GLboolean normalized = %u, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)", @@ -4936,7 +5024,7 @@ void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLbo } } -void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height); @@ -4955,7 +5043,7 @@ void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) // OpenGL ES 3.0 functions -void __stdcall glReadBuffer(GLenum mode) +void GL_APIENTRY glReadBuffer(GLenum mode) { EVENT("(GLenum mode = 0x%X)", mode); @@ -4973,7 +5061,7 @@ void __stdcall glReadBuffer(GLenum mode) } } -void __stdcall glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) +void GL_APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices) { EVENT("(GLenum mode = 0x%X, GLuint start = %u, GLuint end = %u, GLsizei count = %d, GLenum type = 0x%X, " "const GLvoid* indices = 0x%0.8p)", mode, start, end, count, type, indices); @@ -4992,7 +5080,7 @@ void __stdcall glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsize } } -void __stdcall glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +void GL_APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, " "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, " @@ -5020,14 +5108,24 @@ void __stdcall glTexImage3D(GLenum target, GLint level, GLint internalformat, GL case GL_TEXTURE_3D: { gl::Texture3D *texture = context->getTexture3D(); - texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_2D_ARRAY: { gl::Texture2DArray *texture = context->getTexture2DArray(); - texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->setImage(level, width, height, depth, internalformat, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -5038,7 +5136,7 @@ void __stdcall glTexImage3D(GLenum target, GLint level, GLint internalformat, GL } } -void __stdcall glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) +void GL_APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " @@ -5073,14 +5171,24 @@ void __stdcall glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint case GL_TEXTURE_3D: { gl::Texture3D *texture = context->getTexture3D(); - texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_2D_ARRAY: { gl::Texture2DArray *texture = context->getTexture2DArray(); - texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + gl::Error error = texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getState().getUnpackState(), pixels); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -5091,7 +5199,7 @@ void __stdcall glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint } } -void __stdcall glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", @@ -5129,11 +5237,16 @@ void __stdcall glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL return; } - texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer); + gl::Error error = texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, " @@ -5168,14 +5281,24 @@ void __stdcall glCompressedTexImage3D(GLenum target, GLint level, GLenum interna case GL_TEXTURE_3D: { gl::Texture3D *texture = context->getTexture3D(); - texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data); + gl::Error error = texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_2D_ARRAY: { gl::Texture2DArray *texture = context->getTexture2DArray(); - texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data); + gl::Error error = texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -5186,7 +5309,7 @@ void __stdcall glCompressedTexImage3D(GLenum target, GLint level, GLenum interna } } -void __stdcall glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) +void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, " @@ -5233,16 +5356,26 @@ void __stdcall glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffs case GL_TEXTURE_3D: { gl::Texture3D *texture = context->getTexture3D(); - texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, data); + gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_2D_ARRAY: { gl::Texture2DArray *texture = context->getTexture2DArray(); - texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, - format, imageSize, data); + gl::Error error = texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, context->getState().getUnpackState(), data); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -5253,7 +5386,7 @@ void __stdcall glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffs } } -void __stdcall glGenQueries(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenQueries(GLsizei n, GLuint* ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); @@ -5279,7 +5412,7 @@ void __stdcall glGenQueries(GLsizei n, GLuint* ids) } } -void __stdcall glDeleteQueries(GLsizei n, const GLuint* ids) +void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint* ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); @@ -5305,7 +5438,7 @@ void __stdcall glDeleteQueries(GLsizei n, const GLuint* ids) } } -GLboolean __stdcall glIsQuery(GLuint id) +GLboolean GL_APIENTRY glIsQuery(GLuint id) { EVENT("(GLuint id = %u)", id); @@ -5324,7 +5457,7 @@ GLboolean __stdcall glIsQuery(GLuint id) return GL_FALSE; } -void __stdcall glBeginQuery(GLenum target, GLuint id) +void GL_APIENTRY glBeginQuery(GLenum target, GLuint id) { EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); @@ -5351,7 +5484,7 @@ void __stdcall glBeginQuery(GLenum target, GLuint id) } } -void __stdcall glEndQuery(GLenum target) +void GL_APIENTRY glEndQuery(GLenum target) { EVENT("(GLenum target = 0x%X)", target); @@ -5378,7 +5511,7 @@ void __stdcall glEndQuery(GLenum target) } } -void __stdcall glGetQueryiv(GLenum target, GLenum pname, GLint* params) +void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params); @@ -5410,7 +5543,7 @@ void __stdcall glGetQueryiv(GLenum target, GLenum pname, GLint* params) } } -void __stdcall glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) +void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) { EVENT("(GLuint id = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", id, pname, params); @@ -5468,7 +5601,7 @@ void __stdcall glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params) } } -GLboolean __stdcall glUnmapBuffer(GLenum target) +GLboolean GL_APIENTRY glUnmapBuffer(GLenum target) { EVENT("(GLenum target = 0x%X)", target); @@ -5487,7 +5620,7 @@ GLboolean __stdcall glUnmapBuffer(GLenum target) return GL_FALSE; } -void __stdcall glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) +void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); @@ -5504,7 +5637,7 @@ void __stdcall glGetBufferPointerv(GLenum target, GLenum pname, GLvoid** params) } } -void __stdcall glDrawBuffers(GLsizei n, const GLenum* bufs) +void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum* bufs) { gl::Context *context = gl::getNonLostContext(); if (context) @@ -5519,7 +5652,7 @@ void __stdcall glDrawBuffers(GLsizei n, const GLenum* bufs) } } -void __stdcall glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5537,7 +5670,7 @@ void __stdcall glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5555,7 +5688,7 @@ void __stdcall glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5573,7 +5706,7 @@ void __stdcall glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5591,7 +5724,7 @@ void __stdcall glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5609,7 +5742,7 @@ void __stdcall glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %u, const GLfloat* value = 0x%0.8p)", location, count, transpose, value); @@ -5627,7 +5760,7 @@ void __stdcall glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean tra } } -void __stdcall glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +void GL_APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, GLint dstX0 = %d, " "GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, GLbitfield mask = 0x%X, GLenum filter = 0x%X)", @@ -5649,12 +5782,17 @@ void __stdcall glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint sr return; } - context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, - mask, filter); + gl::Error error = context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", target, samples, internalformat, width, height); @@ -5674,11 +5812,12 @@ void __stdcall glRenderbufferStorageMultisample(GLenum target, GLsizei samples, return; } - context->setRenderbufferStorage(width, height, internalformat, samples); + gl::Renderbuffer *renderbuffer = context->getState().getCurrentRenderbuffer(); + renderbuffer->setStorage(width, height, internalformat, samples); } } -void __stdcall glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) +void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) { EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, GLint layer = %d)", target, attachment, texture, level, layer); @@ -5695,27 +5834,20 @@ void __stdcall glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuin gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); ASSERT(framebuffer); - gl::Texture *textureObject = context->getTexture(texture); - GLenum textarget = textureObject ? textureObject->getTarget() : GL_NONE; - - if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT) + if (texture != 0) { - const unsigned int colorAttachment = (attachment - GL_COLOR_ATTACHMENT0_EXT); - framebuffer->setColorbuffer(colorAttachment, textarget, texture, level, layer); + gl::Texture *textureObject = context->getTexture(texture); + gl::ImageIndex index(textureObject->getTarget(), level, layer); + framebuffer->setTextureAttachment(attachment, textureObject, index); } else { - switch (attachment) - { - case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level, layer); break; - case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level, layer); break; - case GL_DEPTH_STENCIL_ATTACHMENT: framebuffer->setDepthStencilBuffer(textarget, texture, level, layer); break; - } + framebuffer->setNULLAttachment(attachment); } } } -GLvoid* __stdcall glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +GLvoid* GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", target, offset, length, access); @@ -5735,7 +5867,7 @@ GLvoid* __stdcall glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr le return NULL; } -void __stdcall glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); @@ -5752,7 +5884,7 @@ void __stdcall glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeip } } -void __stdcall glBindVertexArray(GLuint array) +void GL_APIENTRY glBindVertexArray(GLuint array) { EVENT("(GLuint array = %u)", array); @@ -5779,7 +5911,7 @@ void __stdcall glBindVertexArray(GLuint array) } } -void __stdcall glDeleteVertexArrays(GLsizei n, const GLuint* arrays) +void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint* arrays) { EVENT("(GLsizei n = %d, const GLuint* arrays = 0x%0.8p)", n, arrays); @@ -5808,7 +5940,7 @@ void __stdcall glDeleteVertexArrays(GLsizei n, const GLuint* arrays) } } -void __stdcall glGenVertexArrays(GLsizei n, GLuint* arrays) +void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint* arrays) { EVENT("(GLsizei n = %d, GLuint* arrays = 0x%0.8p)", n, arrays); @@ -5834,7 +5966,7 @@ void __stdcall glGenVertexArrays(GLsizei n, GLuint* arrays) } } -GLboolean __stdcall glIsVertexArray(GLuint array) +GLboolean GL_APIENTRY glIsVertexArray(GLuint array) { EVENT("(GLuint array = %u)", array); @@ -5860,7 +5992,7 @@ GLboolean __stdcall glIsVertexArray(GLuint array) return GL_FALSE; } -void __stdcall glGetIntegeri_v(GLenum target, GLuint index, GLint* data) +void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint* data) { EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint* data = 0x%0.8p)", target, index, data); @@ -5941,7 +6073,7 @@ void __stdcall glGetIntegeri_v(GLenum target, GLuint index, GLint* data) } } -void __stdcall glBeginTransformFeedback(GLenum primitiveMode) +void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode) { EVENT("(GLenum primitiveMode = 0x%X)", primitiveMode); @@ -5986,7 +6118,7 @@ void __stdcall glBeginTransformFeedback(GLenum primitiveMode) } } -void __stdcall glEndTransformFeedback(void) +void GL_APIENTRY glEndTransformFeedback(void) { EVENT("(void)"); @@ -6012,7 +6144,7 @@ void __stdcall glEndTransformFeedback(void) } } -void __stdcall glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) +void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) { EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u, GLintptr offset = %d, GLsizeiptr size = %d)", target, index, buffer, offset, size); @@ -6090,7 +6222,7 @@ void __stdcall glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLi } } -void __stdcall glBindBufferBase(GLenum target, GLuint index, GLuint buffer) +void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer) { EVENT("(GLenum target = 0x%X, GLuint index = %u, GLuint buffer = %u)", target, index, buffer); @@ -6146,7 +6278,7 @@ void __stdcall glBindBufferBase(GLenum target, GLuint index, GLuint buffer) } } -void __stdcall glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) +void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode) { EVENT("(GLuint program = %u, GLsizei count = %d, const GLchar* const* varyings = 0x%0.8p, GLenum bufferMode = 0x%X)", program, count, varyings, bufferMode); @@ -6195,7 +6327,7 @@ void __stdcall glTransformFeedbackVaryings(GLuint program, GLsizei count, const } } -void __stdcall glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) +void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name) { EVENT("(GLuint program = %u, GLuint index = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, " "GLsizei* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)", @@ -6234,7 +6366,7 @@ void __stdcall glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsiz } } -void __stdcall glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) +void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) { EVENT("(GLuint index = %u, GLint size = %d, GLenum type = 0x%X, GLsizei stride = %d, const GLvoid* pointer = 0x%0.8p)", index, size, type, stride, pointer); @@ -6304,7 +6436,7 @@ void __stdcall glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLs } } -void __stdcall glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) +void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) { EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params); @@ -6346,7 +6478,7 @@ void __stdcall glGetVertexAttribIiv(GLuint index, GLenum pname, GLint* params) } } -void __stdcall glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) +void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) { EVENT("(GLuint index = %u, GLenum pname = 0x%X, GLuint* params = 0x%0.8p)", index, pname, params); @@ -6388,7 +6520,7 @@ void __stdcall glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params) } } -void __stdcall glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) +void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { EVENT("(GLuint index = %u, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)", index, x, y, z, w); @@ -6413,7 +6545,7 @@ void __stdcall glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint } } -void __stdcall glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) +void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { EVENT("(GLuint index = %u, GLuint x = %u, GLuint y = %u, GLuint z = %u, GLuint w = %u)", index, x, y, z, w); @@ -6438,7 +6570,7 @@ void __stdcall glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GL } } -void __stdcall glVertexAttribI4iv(GLuint index, const GLint* v) +void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint* v) { EVENT("(GLuint index = %u, const GLint* v = 0x%0.8p)", index, v); @@ -6461,7 +6593,7 @@ void __stdcall glVertexAttribI4iv(GLuint index, const GLint* v) } } -void __stdcall glVertexAttribI4uiv(GLuint index, const GLuint* v) +void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint* v) { EVENT("(GLuint index = %u, const GLuint* v = 0x%0.8p)", index, v); @@ -6484,7 +6616,7 @@ void __stdcall glVertexAttribI4uiv(GLuint index, const GLuint* v) } } -void __stdcall glGetUniformuiv(GLuint program, GLint location, GLuint* params) +void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint* params) { EVENT("(GLuint program = %u, GLint location = %d, GLuint* params = 0x%0.8p)", program, location, params); @@ -6506,7 +6638,7 @@ void __stdcall glGetUniformuiv(GLuint program, GLint location, GLuint* params) } } -GLint __stdcall glGetFragDataLocation(GLuint program, const GLchar *name) +GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name) { EVENT("(GLuint program = %u, const GLchar *name = 0x%0.8p)", program, name); @@ -6547,30 +6679,30 @@ GLint __stdcall glGetFragDataLocation(GLuint program, const GLchar *name) return 0; } -void __stdcall glUniform1ui(GLint location, GLuint v0) +void GL_APIENTRY glUniform1ui(GLint location, GLuint v0) { glUniform1uiv(location, 1, &v0); } -void __stdcall glUniform2ui(GLint location, GLuint v0, GLuint v1) +void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1) { const GLuint xy[] = { v0, v1 }; glUniform2uiv(location, 1, xy); } -void __stdcall glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) +void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2) { const GLuint xyz[] = { v0, v1, v2 }; glUniform3uiv(location, 1, xyz); } -void __stdcall glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) { const GLuint xyzw[] = { v0, v1, v2, v3 }; glUniform4uiv(location, 1, xyzw); } -void __stdcall glUniform1uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint* value) { EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", location, count, value); @@ -6588,7 +6720,7 @@ void __stdcall glUniform1uiv(GLint location, GLsizei count, const GLuint* value) } } -void __stdcall glUniform2uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint* value) { EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", location, count, value); @@ -6606,7 +6738,7 @@ void __stdcall glUniform2uiv(GLint location, GLsizei count, const GLuint* value) } } -void __stdcall glUniform3uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint* value) { EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value)", location, count, value); @@ -6624,7 +6756,7 @@ void __stdcall glUniform3uiv(GLint location, GLsizei count, const GLuint* value) } } -void __stdcall glUniform4uiv(GLint location, GLsizei count, const GLuint* value) +void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint* value) { EVENT("(GLint location = %d, GLsizei count = %d, const GLuint* value = 0x%0.8p)", location, count, value); @@ -6642,7 +6774,7 @@ void __stdcall glUniform4uiv(GLint location, GLsizei count, const GLuint* value) } } -void __stdcall glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) +void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint* value = 0x%0.8p)", buffer, drawbuffer, value); @@ -6687,7 +6819,7 @@ void __stdcall glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* val } } -void __stdcall glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) +void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint* value = 0x%0.8p)", buffer, drawbuffer, value); @@ -6724,7 +6856,7 @@ void __stdcall glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* v } } -void __stdcall glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) +void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat* value = 0x%0.8p)", buffer, drawbuffer, value); @@ -6769,7 +6901,7 @@ void __stdcall glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* v } } -void __stdcall glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) +void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { EVENT("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth, GLint stencil = %d)", buffer, drawbuffer, depth, stencil); @@ -6806,7 +6938,7 @@ void __stdcall glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, G } } -const GLubyte* __stdcall glGetStringi(GLenum name, GLuint index) +const GLubyte* GL_APIENTRY glGetStringi(GLenum name, GLuint index) { EVENT("(GLenum name = 0x%X, GLuint index = %u)", name, index); @@ -6837,7 +6969,7 @@ const GLubyte* __stdcall glGetStringi(GLenum name, GLuint index) return NULL; } -void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) +void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { EVENT("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)", readTarget, writeTarget, readOffset, writeOffset, size); @@ -6851,7 +6983,7 @@ void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintp return; } - if (!gl::ValidBufferTarget(context, readTarget) || !gl::ValidBufferTarget(context, readTarget)) + if (!gl::ValidBufferTarget(context, readTarget) || !gl::ValidBufferTarget(context, writeTarget)) { context->recordError(gl::Error(GL_INVALID_ENUM)); return; @@ -6881,7 +7013,7 @@ void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintp return; } - if (readBuffer == writeBuffer && abs(readOffset - writeOffset) < size) + if (readBuffer == writeBuffer && std::abs(readOffset - writeOffset) < size) { context->recordError(gl::Error(GL_INVALID_VALUE)); return; @@ -6900,7 +7032,7 @@ void __stdcall glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintp } } -void __stdcall glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) +void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices) { EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLchar* const* uniformNames = 0x%0.8p, GLuint* uniformIndices = 0x%0.8p)", program, uniformCount, uniformNames, uniformIndices); @@ -6954,7 +7086,7 @@ void __stdcall glGetUniformIndices(GLuint program, GLsizei uniformCount, const G } } -void __stdcall glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) +void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params) { EVENT("(GLuint program = %u, GLsizei uniformCount = %d, const GLuint* uniformIndices = 0x%0.8p, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", program, uniformCount, uniformIndices, pname, params); @@ -7034,7 +7166,7 @@ void __stdcall glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const } } -GLuint __stdcall glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) +GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName) { EVENT("(GLuint program = %u, const GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockName); @@ -7075,7 +7207,7 @@ GLuint __stdcall glGetUniformBlockIndex(GLuint program, const GLchar* uniformBlo return 0; } -void __stdcall glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) +void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) { EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", program, uniformBlockIndex, pname, params); @@ -7134,7 +7266,7 @@ void __stdcall glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockInde } } -void __stdcall glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) +void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName) { EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLchar* uniformBlockName = 0x%0.8p)", program, uniformBlockIndex, bufSize, length, uniformBlockName); @@ -7176,7 +7308,7 @@ void __stdcall glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIn } } -void __stdcall glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) { EVENT("(GLuint program = %u, GLuint uniformBlockIndex = %u, GLuint uniformBlockBinding = %u)", program, uniformBlockIndex, uniformBlockBinding); @@ -7225,7 +7357,7 @@ void __stdcall glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, G } } -void __stdcall glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) +void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount) { EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)", mode, first, count, instanceCount); @@ -7244,7 +7376,7 @@ void __stdcall glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GL } } -void __stdcall glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) +void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount) { EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p, GLsizei instanceCount = %d)", mode, count, type, indices, instanceCount); @@ -7263,7 +7395,7 @@ void __stdcall glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, } } -GLsync __stdcall glFenceSync(GLenum condition, GLbitfield flags) +GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags) { EVENT("(GLenum condition = 0x%X, GLbitfield flags = 0x%X)", condition, flags); @@ -7288,13 +7420,24 @@ GLsync __stdcall glFenceSync(GLenum condition, GLbitfield flags) return 0; } - return context->createFenceSync(condition); + GLsync fenceSync = context->createFenceSync(); + + gl::FenceSync *fenceSyncObject = context->getFenceSync(fenceSync); + gl::Error error = fenceSyncObject->set(condition); + if (error.isError()) + { + context->deleteFenceSync(fenceSync); + context->recordError(error); + return NULL; + } + + return fenceSync; } return NULL; } -GLboolean __stdcall glIsSync(GLsync sync) +GLboolean GL_APIENTRY glIsSync(GLsync sync) { EVENT("(GLsync sync = 0x%0.8p)", sync); @@ -7313,7 +7456,7 @@ GLboolean __stdcall glIsSync(GLsync sync) return GL_FALSE; } -void __stdcall glDeleteSync(GLsync sync) +void GL_APIENTRY glDeleteSync(GLsync sync) { EVENT("(GLsync sync = 0x%0.8p)", sync); @@ -7336,7 +7479,7 @@ void __stdcall glDeleteSync(GLsync sync) } } -GLenum __stdcall glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", sync, flags, timeout); @@ -7364,13 +7507,21 @@ GLenum __stdcall glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeou return GL_WAIT_FAILED; } - return fenceSync->clientWait(flags, timeout); + GLenum result = GL_WAIT_FAILED; + gl::Error error = fenceSync->clientWait(flags, timeout, &result); + if (error.isError()) + { + context->recordError(error); + return GL_WAIT_FAILED; + } + + return result; } return GL_FALSE; } -void __stdcall glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) +void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) { EVENT("(GLsync sync = 0x%0.8p, GLbitfield flags = 0x%X, GLuint64 timeout = %llu)", sync, flags, timeout); @@ -7404,11 +7555,15 @@ void __stdcall glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) return; } - fenceSync->serverWait(); + gl::Error error = fenceSync->serverWait(flags, timeout); + if (error.isError()) + { + context->recordError(error); + } } } -void __stdcall glGetInteger64v(GLenum pname, GLint64* params) +void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64* params) { EVENT("(GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", pname, params); @@ -7440,7 +7595,7 @@ void __stdcall glGetInteger64v(GLenum pname, GLint64* params) } } -void __stdcall glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) +void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { EVENT("(GLsync sync = 0x%0.8p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLint* values = 0x%0.8p)", sync, pname, bufSize, length, values); @@ -7471,10 +7626,20 @@ void __stdcall glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* switch (pname) { case GL_OBJECT_TYPE: values[0] = static_cast(GL_SYNC_FENCE); break; - case GL_SYNC_STATUS: values[0] = static_cast(fenceSync->getStatus()); break; case GL_SYNC_CONDITION: values[0] = static_cast(fenceSync->getCondition()); break; case GL_SYNC_FLAGS: values[0] = 0; break; + case GL_SYNC_STATUS: + { + gl::Error error = fenceSync->getStatus(values); + if (error.isError()) + { + context->recordError(error); + return; + } + break; + } + default: context->recordError(gl::Error(GL_INVALID_ENUM)); return; @@ -7482,7 +7647,7 @@ void __stdcall glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* } } -void __stdcall glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) +void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) { EVENT("(GLenum target = 0x%X, GLuint index = %u, GLint64* data = 0x%0.8p)", target, index, data); @@ -7558,7 +7723,7 @@ void __stdcall glGetInteger64i_v(GLenum target, GLuint index, GLint64* data) } } -void __stdcall glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) +void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64* params = 0x%0.8p)", target, pname, params); @@ -7618,7 +7783,7 @@ void __stdcall glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64* pa } } -void __stdcall glGenSamplers(GLsizei count, GLuint* samplers) +void GL_APIENTRY glGenSamplers(GLsizei count, GLuint* samplers) { EVENT("(GLsizei count = %d, GLuint* samplers = 0x%0.8p)", count, samplers); @@ -7644,7 +7809,7 @@ void __stdcall glGenSamplers(GLsizei count, GLuint* samplers) } } -void __stdcall glDeleteSamplers(GLsizei count, const GLuint* samplers) +void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint* samplers) { EVENT("(GLsizei count = %d, const GLuint* samplers = 0x%0.8p)", count, samplers); @@ -7670,7 +7835,7 @@ void __stdcall glDeleteSamplers(GLsizei count, const GLuint* samplers) } } -GLboolean __stdcall glIsSampler(GLuint sampler) +GLboolean GL_APIENTRY glIsSampler(GLuint sampler) { EVENT("(GLuint sampler = %u)", sampler); @@ -7689,7 +7854,7 @@ GLboolean __stdcall glIsSampler(GLuint sampler) return GL_FALSE; } -void __stdcall glBindSampler(GLuint unit, GLuint sampler) +void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler) { EVENT("(GLuint unit = %u, GLuint sampler = %u)", unit, sampler); @@ -7718,7 +7883,7 @@ void __stdcall glBindSampler(GLuint unit, GLuint sampler) } } -void __stdcall glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) +void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) { EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint param = %d)", sampler, pname, param); @@ -7751,12 +7916,12 @@ void __stdcall glSamplerParameteri(GLuint sampler, GLenum pname, GLint param) } } -void __stdcall glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) +void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param) { glSamplerParameteri(sampler, pname, *param); } -void __stdcall glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) +void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) { EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLfloat param = %g)", sampler, pname, param); @@ -7789,12 +7954,12 @@ void __stdcall glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) } } -void __stdcall glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) +void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param) { glSamplerParameterf(sampler, pname, *param); } -void __stdcall glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) +void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) { EVENT("(GLuint sampler = %u, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", sampler, pname, params); @@ -7822,7 +7987,7 @@ void __stdcall glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* para } } -void __stdcall glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) +void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) { EVENT("(GLuint sample = %ur, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", sampler, pname, params); @@ -7850,7 +8015,7 @@ void __stdcall glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* pa } } -void __stdcall glVertexAttribDivisor(GLuint index, GLuint divisor) +void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor) { EVENT("(GLuint index = %u, GLuint divisor = %u)", index, divisor); @@ -7873,7 +8038,7 @@ void __stdcall glVertexAttribDivisor(GLuint index, GLuint divisor) } } -void __stdcall glBindTransformFeedback(GLenum target, GLuint id) +void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id) { EVENT("(GLenum target = 0x%X, GLuint id = %u)", target, id); @@ -7916,7 +8081,7 @@ void __stdcall glBindTransformFeedback(GLenum target, GLuint id) } } -void __stdcall glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) +void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) { EVENT("(GLsizei n = %d, const GLuint* ids = 0x%0.8p)", n, ids); @@ -7936,7 +8101,7 @@ void __stdcall glDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) } } -void __stdcall glGenTransformFeedbacks(GLsizei n, GLuint* ids) +void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint* ids) { EVENT("(GLsizei n = %d, GLuint* ids = 0x%0.8p)", n, ids); @@ -7956,7 +8121,7 @@ void __stdcall glGenTransformFeedbacks(GLsizei n, GLuint* ids) } } -GLboolean __stdcall glIsTransformFeedback(GLuint id) +GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id) { EVENT("(GLuint id = %u)", id); @@ -7975,7 +8140,7 @@ GLboolean __stdcall glIsTransformFeedback(GLuint id) return GL_FALSE; } -void __stdcall glPauseTransformFeedback(void) +void GL_APIENTRY glPauseTransformFeedback(void) { EVENT("(void)"); @@ -8002,7 +8167,7 @@ void __stdcall glPauseTransformFeedback(void) } } -void __stdcall glResumeTransformFeedback(void) +void GL_APIENTRY glResumeTransformFeedback(void) { EVENT("(void)"); @@ -8029,7 +8194,7 @@ void __stdcall glResumeTransformFeedback(void) } } -void __stdcall glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) +void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary) { EVENT("(GLuint program = %u, GLsizei bufSize = %d, GLsizei* length = 0x%0.8p, GLenum* binaryFormat = 0x%0.8p, GLvoid* binary = 0x%0.8p)", program, bufSize, length, binaryFormat, binary); @@ -8048,7 +8213,7 @@ void __stdcall glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* leng } } -void __stdcall glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) +void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length) { EVENT("(GLuint program = %u, GLenum binaryFormat = 0x%X, const GLvoid* binary = 0x%0.8p, GLsizei length = %d)", program, binaryFormat, binary, length); @@ -8067,7 +8232,7 @@ void __stdcall glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid } } -void __stdcall glProgramParameteri(GLuint program, GLenum pname, GLint value) +void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value) { EVENT("(GLuint program = %u, GLenum pname = 0x%X, GLint value = %d)", program, pname, value); @@ -8086,7 +8251,7 @@ void __stdcall glProgramParameteri(GLuint program, GLenum pname, GLint value) } } -void __stdcall glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) +void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments) { EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p)", target, numAttachments, attachments); @@ -8106,14 +8271,21 @@ void __stdcall glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, co } gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - if (framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + ASSERT(framebuffer); + + if (framebuffer->completeness(context->getData()) == GL_FRAMEBUFFER_COMPLETE) { - framebuffer->invalidate(context->getCaps(), numAttachments, attachments); + gl::Error error = framebuffer->invalidate(context->getCaps(), numAttachments, attachments); + if (error.isError()) + { + context->recordError(error); + return; + } } } } -void __stdcall glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) +void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum* attachments = 0x%0.8p, GLint x = %d, " "GLint y = %d, GLsizei width = %d, GLsizei height = %d)", @@ -8134,14 +8306,21 @@ void __stdcall glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, } gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target); - if (framebuffer && framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE) + ASSERT(framebuffer); + + if (framebuffer->completeness(context->getData()) == GL_FRAMEBUFFER_COMPLETE) { - framebuffer->invalidateSub(context->getCaps(), numAttachments, attachments, x, y, width, height); + gl::Error error = framebuffer->invalidateSub(numAttachments, attachments, x, y, width, height); + if (error.isError()) + { + context->recordError(error); + return; + } } } } -void __stdcall glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) +void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)", target, levels, internalformat, width, height); @@ -8165,14 +8344,24 @@ void __stdcall glTexStorage2D(GLenum target, GLsizei levels, GLenum internalform case GL_TEXTURE_2D: { gl::Texture2D *texture2d = context->getTexture2D(); - texture2d->storage(levels, internalformat, width, height); + gl::Error error = texture2d->storage(levels, internalformat, width, height); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_CUBE_MAP: { gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); - textureCube->storage(levels, internalformat, width); + gl::Error error = textureCube->storage(levels, internalformat, width); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -8183,7 +8372,7 @@ void __stdcall glTexStorage2D(GLenum target, GLsizei levels, GLenum internalform } } -void __stdcall glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { EVENT("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, " "GLsizei height = %d, GLsizei depth = %d)", @@ -8208,14 +8397,24 @@ void __stdcall glTexStorage3D(GLenum target, GLsizei levels, GLenum internalform case GL_TEXTURE_3D: { gl::Texture3D *texture3d = context->getTexture3D(); - texture3d->storage(levels, internalformat, width, height, depth); + gl::Error error = texture3d->storage(levels, internalformat, width, height, depth); + if (error.isError()) + { + context->recordError(error); + return; + } } break; case GL_TEXTURE_2D_ARRAY: { gl::Texture2DArray *texture2darray = context->getTexture2DArray(); - texture2darray->storage(levels, internalformat, width, height, depth); + gl::Error error = texture2darray->storage(levels, internalformat, width, height, depth); + if (error.isError()) + { + context->recordError(error); + return; + } } break; @@ -8225,7 +8424,7 @@ void __stdcall glTexStorage3D(GLenum target, GLsizei levels, GLenum internalform } } -void __stdcall glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) +void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params) { EVENT("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, " "GLint* params = 0x%0.8p)", @@ -8281,7 +8480,7 @@ void __stdcall glGetInternalformativ(GLenum target, GLenum internalformat, GLenu // Extension functions -void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, +void GL_APIENTRY glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, " @@ -8299,12 +8498,17 @@ void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLi return; } - context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, - mask, filter); + gl::Error error = context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, +void GL_APIENTRY glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " @@ -8315,7 +8519,7 @@ void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat UNIMPLEMENTED(); // FIXME } -void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, +void GL_APIENTRY glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary) { EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)", @@ -8340,15 +8544,16 @@ void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *l return; } - if (!programBinary->save(binaryFormat, binary, bufSize, length)) + gl::Error error = programBinary->save(binaryFormat, binary, bufSize, length); + if (error.isError()) { - context->recordError(gl::Error(GL_INVALID_OPERATION)); + context->recordError(error); return; } } } -void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, +void GL_APIENTRY glProgramBinaryOES(GLuint program, GLenum binaryFormat, const void *binary, GLint length) { EVENT("(GLenum program = 0x%X, binaryFormat = 0x%x, binary = 0x%0.8p, length = %d)", @@ -8371,11 +8576,16 @@ void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, return; } - context->setProgramBinary(program, binaryFormat, binary, length); + gl::Error error = context->setProgramBinary(program, binaryFormat, binary, length); + if (error.isError()) + { + context->recordError(error); + return; + } } } -void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) +void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) { EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs); @@ -8388,6 +8598,8 @@ void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) return; } + ASSERT(context->getState().getDrawFramebuffer()); + if (context->getState().getDrawFramebuffer()->id() == 0) { if (n != 1) @@ -8416,6 +8628,7 @@ void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) } gl::Framebuffer *framebuffer = context->getState().getDrawFramebuffer(); + ASSERT(framebuffer); for (unsigned int colorAttachment = 0; colorAttachment < static_cast(n); colorAttachment++) { @@ -8429,7 +8642,7 @@ void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs) } } -void __stdcall glGetBufferPointervOES(GLenum target, GLenum pname, void** params) +void GL_APIENTRY glGetBufferPointervOES(GLenum target, GLenum pname, void** params) { EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLvoid** params = 0x%0.8p)", target, pname, params); @@ -8461,7 +8674,7 @@ void __stdcall glGetBufferPointervOES(GLenum target, GLenum pname, void** params } } -void * __stdcall glMapBufferOES(GLenum target, GLenum access) +void * GL_APIENTRY glMapBufferOES(GLenum target, GLenum access) { EVENT("(GLenum target = 0x%X, GLbitfield access = 0x%X)", target, access); @@ -8507,7 +8720,7 @@ void * __stdcall glMapBufferOES(GLenum target, GLenum access) return NULL; } -GLboolean __stdcall glUnmapBufferOES(GLenum target) +GLboolean GL_APIENTRY glUnmapBufferOES(GLenum target) { EVENT("(GLenum target = 0x%X)", target); @@ -8543,7 +8756,7 @@ GLboolean __stdcall glUnmapBufferOES(GLenum target) return GL_FALSE; } -void* __stdcall glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) +void* GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = 0x%X)", target, offset, length, access); @@ -8638,7 +8851,7 @@ void* __stdcall glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr return NULL; } -void __stdcall glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length) +void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length) { EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)", target, offset, length); @@ -8686,7 +8899,7 @@ void __stdcall glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsi } } -__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname) +__eglMustCastToProperFunctionPointerType EGLAPIENTRY glGetProcAddress(const char *procname) { struct Extension { @@ -8744,7 +8957,7 @@ __eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char * // Non-public functions used by EGL -bool __stdcall glBindTexImage(egl::Surface *surface) +bool EGLAPIENTRY glBindTexImage(egl::Surface *surface) { EVENT("(egl::Surface* surface = 0x%0.8p)", surface); diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp index 51447e273a..00f63ae079 100644 --- a/src/3rdparty/angle/src/libGLESv2/main.cpp +++ b/src/3rdparty/angle/src/libGLESv2/main.cpp @@ -11,24 +11,42 @@ #include "common/tls.h" -#if defined(ANGLE_PLATFORM_WINRT) -__declspec(thread) -#endif -static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; +static TLSIndex currentTLS = TLS_INVALID_INDEX; namespace gl { +// TODO(kbr): figure out how these are going to be managed on +// non-Windows platforms. These routines would need to be exported +// from ANGLE and called cooperatively when users create and destroy +// threads -- or the initialization of the TLS index, and allocation +// of thread-local data, will have to be done lazily. Will have to use +// destructor function with pthread_create_key on POSIX platforms to +// clean up thread-local data. + +// Call this exactly once at process startup. +bool CreateThreadLocalIndex() +{ + currentTLS = CreateTLSIndex(); + if (currentTLS == TLS_INVALID_INDEX) + { + return false; + } + return true; +} + +// Call this exactly once at process shutdown. +void DestroyThreadLocalIndex() +{ + DestroyTLSIndex(currentTLS); + currentTLS = TLS_INVALID_INDEX; +} + +// Call this upon thread startup. Current *AllocateCurrent() { -#if defined(ANGLE_PLATFORM_WINRT) - if (currentTLS == TLS_OUT_OF_INDEXES) - { - currentTLS = CreateTLSIndex(); - } -#endif - ASSERT(currentTLS != TLS_OUT_OF_INDEXES); - if (currentTLS == TLS_OUT_OF_INDEXES) + ASSERT(currentTLS != TLS_INVALID_INDEX); + if (currentTLS == TLS_INVALID_INDEX) { return NULL; } @@ -46,14 +64,9 @@ Current *AllocateCurrent() return current; } +// Call this upon thread shutdown. void DeallocateCurrent() { -#if defined(ANGLE_PLATFORM_WINRT) - if (currentTLS == TLS_OUT_OF_INDEXES) - { - return; - } -#endif Current *current = reinterpret_cast(GetTLSValue(currentTLS)); SafeDelete(current); SetTLSValue(currentTLS, NULL); @@ -61,22 +74,21 @@ void DeallocateCurrent() } -#ifndef QT_OPENGL_ES_2_ANGLE_STATIC - +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) { case DLL_PROCESS_ATTACH: { -#if defined(ANGLE_PLATFORM_WINRT) // On WinRT, don't handle TLS from DllMain - return DisableThreadLibraryCalls(instance); -#endif - currentTLS = CreateTLSIndex(); - if (currentTLS == TLS_OUT_OF_INDEXES) + if (!gl::CreateThreadLocalIndex()) { return FALSE; } + +#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS + gl::InitializeDebugAnnotations(); +#endif } // Fall through to initialize index case DLL_THREAD_ATTACH: @@ -91,9 +103,11 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved break; case DLL_PROCESS_DETACH: { -#if !defined(ANGLE_PLATFORM_WINRT) gl::DeallocateCurrent(); - DestroyTLSIndex(currentTLS); + gl::DestroyThreadLocalIndex(); + +#ifdef ANGLE_ENABLE_DEBUG_ANNOTATIONS + gl::UninitializeDebugAnnotations(); #endif } break; @@ -103,8 +117,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved return TRUE; } - -#endif // !QT_OPENGL_ES_2_ANGLE_STATIC +#endif // ANGLE_PLATFORM_WINDOWS && !QT_OPENGL_ES_2_ANGLE_STATIC namespace gl { @@ -152,7 +165,7 @@ Context *getNonLostContext() { if (context->isContextLost()) { - gl::error(GL_OUT_OF_MEMORY); + context->recordError(Error(GL_OUT_OF_MEMORY, "Context has been lost.")); return NULL; } else @@ -170,32 +183,4 @@ egl::Display *getDisplay() return current->display; } -// Records an error code -void error(GLenum errorCode) -{ - gl::Context *context = glGetCurrentContext(); - context->recordError(Error(errorCode)); - - switch (errorCode) - { - case GL_INVALID_ENUM: - TRACE("\t! Error generated: invalid enum\n"); - break; - case GL_INVALID_VALUE: - TRACE("\t! Error generated: invalid value\n"); - break; - case GL_INVALID_OPERATION: - TRACE("\t! Error generated: invalid operation\n"); - break; - case GL_OUT_OF_MEMORY: - TRACE("\t! Error generated: out of memory\n"); - break; - case GL_INVALID_FRAMEBUFFER_OPERATION: - TRACE("\t! Error generated: invalid framebuffer operation\n"); - break; - default: UNREACHABLE(); - } } - -} - diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h index c30ad3375c..dff02787f5 100644 --- a/src/3rdparty/angle/src/libGLESv2/main.h +++ b/src/3rdparty/angle/src/libGLESv2/main.h @@ -14,14 +14,11 @@ #include #include -#ifndef Sleep -#define Sleep(ms) WaitForSingleObjectEx(GetCurrentThread(), ms, FALSE) -#endif - namespace egl { class Display; class Surface; +class AttributeMap; } namespace gl @@ -40,16 +37,6 @@ Context *getContext(); Context *getNonLostContext(); egl::Display *getDisplay(); -void error(GLenum errorCode); - -template -const T &error(GLenum errorCode, const T &returnValue) -{ - error(errorCode); - - return returnValue; -} - } namespace rx @@ -64,11 +51,11 @@ gl::Context *glCreateContext(int clientVersion, const gl::Context *shareContext, void glDestroyContext(gl::Context *context); void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); gl::Context *glGetCurrentContext(); -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType); +rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attribMap); void glDestroyRenderer(rx::Renderer *renderer); -__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname); -bool __stdcall glBindTexImage(egl::Surface *surface); +__eglMustCastToProperFunctionPointerType EGLAPIENTRY glGetProcAddress(const char *procname); +bool EGLAPIENTRY glBindTexImage(egl::Surface *surface); } #endif // LIBGLESV2_MAIN_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h index f0b5f02227..c031effabd 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/BufferImpl.h @@ -12,6 +12,8 @@ #include "common/angleutils.h" #include "libGLESv2/Buffer.h" +#include + namespace rx { @@ -21,7 +23,6 @@ class BufferImpl virtual ~BufferImpl() { } virtual gl::Error setData(const void* data, size_t size, GLenum usage) = 0; - virtual void *getData() = 0; virtual gl::Error setSubData(const void* data, size_t size, size_t offset) = 0; virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size) = 0; virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr) = 0; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h index d54e6becd3..1dd46785d9 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/FenceImpl.h @@ -4,29 +4,47 @@ // found in the LICENSE file. // -// FenceImpl.h: Defines the rx::FenceImpl class. +// FenceImpl.h: Defines the rx::FenceNVImpl and rx::FenceSyncImpl classes. #ifndef LIBGLESV2_RENDERER_FENCEIMPL_H_ #define LIBGLESV2_RENDERER_FENCEIMPL_H_ +#include "libGLESv2/Error.h" + #include "common/angleutils.h" +#include "angle_gl.h" + namespace rx { -class FenceImpl +class FenceNVImpl { public: - FenceImpl() { }; - virtual ~FenceImpl() { }; + FenceNVImpl() { }; + virtual ~FenceNVImpl() { }; - virtual bool isSet() const = 0; - virtual void set() = 0; - virtual bool test(bool flushCommandBuffer) = 0; - virtual bool hasError() const = 0; + virtual gl::Error set() = 0; + virtual gl::Error test(bool flushCommandBuffer, GLboolean *outFinished) = 0; + virtual gl::Error finishFence(GLboolean *outFinished) = 0; private: - DISALLOW_COPY_AND_ASSIGN(FenceImpl); + DISALLOW_COPY_AND_ASSIGN(FenceNVImpl); +}; + +class FenceSyncImpl +{ + public: + FenceSyncImpl() { }; + virtual ~FenceSyncImpl() { }; + + virtual gl::Error set() = 0; + virtual gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) = 0; + virtual gl::Error serverWait(GLbitfield flags, GLuint64 timeout) = 0; + virtual gl::Error getStatus(GLint *outResult) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(FenceSyncImpl); }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp index 370b086233..5b9b75f562 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Image.cpp @@ -4,18 +4,20 @@ // found in the LICENSE file. // -// Image.h: Implements the rx::Image class, an abstract base class for the +// Image.h: Implements the rx::Image class, an abstract base class for the // renderer-specific classes which will define the interface to the underlying // surfaces or resources. #include "libGLESv2/renderer/Image.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/main.h" namespace rx { Image::Image() { - mWidth = 0; + mWidth = 0; mHeight = 0; mDepth = 0; mInternalFormat = GL_NONE; @@ -25,4 +27,20 @@ Image::Image() mDirty = false; } +gl::Error Image::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, gl::Framebuffer *source) +{ + gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget *renderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) + { + return error; + } + + ASSERT(renderTarget); + return copy(xoffset, yoffset, zoffset, area, renderTarget); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h b/src/3rdparty/angle/src/libGLESv2/renderer/Image.h index 3bfc663762..9071a88c67 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Image.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Image.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // -// Image.h: Defines the rx::Image class, an abstract base class for the +// Image.h: Defines the rx::Image class, an abstract base class for the // renderer-specific classes which will define the interface to the underlying // surfaces or resources. @@ -12,18 +12,22 @@ #define LIBGLESV2_RENDERER_IMAGE_H_ #include "common/debug.h" +#include "libGLESv2/Error.h" #include namespace gl { class Framebuffer; +struct Rectangle; +struct ImageIndex; } namespace rx { - -class Renderer; +class RendererD3D; +class RenderTarget; +class TextureStorage; class Image { @@ -43,14 +47,17 @@ class Image void markClean() {mDirty = false;} virtual bool isDirty() const = 0; - virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0; + virtual bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0; - virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) = 0; - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) = 0; + virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) = 0; + virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) = 0; - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source); + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) = 0; + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0; protected: GLsizei mWidth; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp index f68ac383de..d472e1499e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp @@ -111,11 +111,7 @@ IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c) bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const { -#if defined(_MSC_VER) && _MSC_VER < 1600 - return std::tr1::make_tuple(type, offset, count) < std::tr1::make_tuple(rhs.type, rhs.offset, rhs.count); -#else return std::make_tuple(type, offset, count) < std::make_tuple(rhs.type, rhs.offset, rhs.count); -#endif } IndexRangeCache::IndexBounds::IndexBounds() diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp new file mode 100644 index 0000000000..f9fcad38a4 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.cpp @@ -0,0 +1,146 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// ProgramD3D.cpp: Defines the rx::ProgramD3D class which implements rx::ProgramImpl. + +#include "libGLESv2/renderer/ProgramImpl.h" + +#include "common/utilities.h" +#include "libGLESv2/main.h" + +namespace rx +{ + +namespace +{ + +unsigned int ParseAndStripArrayIndex(std::string* name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name->find_last_of('['); + size_t close = name->find_last_of(']'); + if (open != std::string::npos && close == name->length() - 1) + { + subscript = atoi(name->substr(open + 1).c_str()); + name->erase(open); + } + + return subscript; +} + +} + +ProgramImpl::~ProgramImpl() +{ + // Ensure that reset was called by the inherited class during destruction + ASSERT(mUniformIndex.size() == 0); +} + +gl::LinkedUniform *ProgramImpl::getUniformByLocation(GLint location) const +{ + ASSERT(location >= 0 && static_cast(location) < mUniformIndex.size()); + return mUniforms[mUniformIndex[location].index]; +} + +gl::LinkedUniform *ProgramImpl::getUniformByName(const std::string &name) const +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + if (mUniforms[uniformIndex]->name == name) + { + return mUniforms[uniformIndex]; + } + } + + return NULL; +} + +gl::UniformBlock *ProgramImpl::getUniformBlockByIndex(GLuint blockIndex) const +{ + ASSERT(blockIndex < mUniformBlocks.size()); + return mUniformBlocks[blockIndex]; +} + +GLint ProgramImpl::getUniformLocation(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniforms = mUniformIndex.size(); + for (unsigned int location = 0; location < numUniforms; location++) + { + if (mUniformIndex[location].name == name) + { + const int index = mUniformIndex[location].index; + const bool isArray = mUniforms[index]->isArray(); + + if ((isArray && mUniformIndex[location].element == subscript) || + (subscript == GL_INVALID_INDEX)) + { + return location; + } + } + } + + return -1; +} + +GLuint ProgramImpl::getUniformIndex(std::string name) +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + // The app is not allowed to specify array indices other than 0 for arrays of basic types + if (subscript != 0 && subscript != GL_INVALID_INDEX) + { + return GL_INVALID_INDEX; + } + + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + if (mUniforms[index]->name == name) + { + if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX) + { + return index; + } + } + } + + return GL_INVALID_INDEX; +} + +GLuint ProgramImpl::getUniformBlockIndex(std::string name) const +{ + unsigned int subscript = ParseAndStripArrayIndex(&name); + + unsigned int numUniformBlocks = mUniformBlocks.size(); + for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++) + { + const gl::UniformBlock &uniformBlock = *mUniformBlocks[blockIndex]; + if (uniformBlock.name == name) + { + const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0); + if (subscript == uniformBlock.elementIndex || arrayElementZero) + { + return blockIndex; + } + } + } + + return GL_INVALID_INDEX; +} + +void ProgramImpl::reset() +{ + SafeDeleteContainer(mUniforms); + mUniformIndex.clear(); + SafeDeleteContainer(mUniformBlocks); + mTransformFeedbackLinkedVaryings.clear(); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h index ba0955fdf8..6aaa23cf89 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/ProgramImpl.h @@ -13,44 +13,113 @@ #include "libGLESv2/BinaryStream.h" #include "libGLESv2/Constants.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Shader.h" +#include "libGLESv2/renderer/Renderer.h" + +#include namespace rx { -class DynamicHLSL; -class Renderer; - class ProgramImpl { -public: - virtual ~ProgramImpl() { } + public: + ProgramImpl() { } + virtual ~ProgramImpl(); - // TODO: Temporary interfaces to ease migration. Remove soon! - virtual Renderer *getRenderer() = 0; - virtual DynamicHLSL *getDynamicHLSL() = 0; - virtual const std::vector &getPixelShaderKey() = 0; + const std::vector &getUniforms() const { return mUniforms; } + const std::vector &getUniformIndices() const { return mUniformIndex; } + const std::vector &getUniformBlocks() const { return mUniformBlocks; } + const std::vector &getTransformFeedbackLinkedVaryings() const { return mTransformFeedbackLinkedVaryings; } + const sh::Attribute *getShaderAttributes() const { return mShaderAttributes; } + + std::vector &getUniforms() { return mUniforms; } + std::vector &getUniformIndices() { return mUniformIndex; } + std::vector &getUniformBlocks() { return mUniformBlocks; } + std::vector &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; } + sh::Attribute *getShaderAttributes() { return mShaderAttributes; } + + gl::LinkedUniform *getUniformByLocation(GLint location) const; + gl::LinkedUniform *getUniformByName(const std::string &name) const; + gl::UniformBlock *getUniformBlockByIndex(GLuint blockIndex) const; + + GLint getUniformLocation(std::string name); + GLuint getUniformIndex(std::string name); + GLuint getUniformBlockIndex(std::string name) const; + + virtual bool usesPointSize() const = 0; + virtual int getShaderVersion() const = 0; + virtual GLenum getTransformFeedbackBufferMode() const = 0; virtual GLenum getBinaryFormat() = 0; - virtual bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; - virtual bool save(gl::BinaryOutputStream *stream) = 0; + virtual gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0; + virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; - virtual rx::ShaderExecutable *getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector &outputSignature, - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers) = 0; - virtual rx::ShaderExecutable *getVertexExecutableForInputLayout(gl::InfoLog &infoLog, - const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], - const sh::Attribute shaderAttributes[], - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers) = 0; + virtual gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) = 0; - virtual bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, int *registers, - std::vector *linkedVaryings, std::map *outputVariables) = 0; + virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform3fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform4fv(GLint location, GLsizei count, const GLfloat *v) = 0; + virtual void setUniform1iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform2iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform3iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform4iv(GLint location, GLsizei count, const GLint *v) = 0; + virtual void setUniform1uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform2uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform3uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniform4uiv(GLint location, GLsizei count, const GLuint *v) = 0; + virtual void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; + virtual void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) = 0; - virtual void initializeUniformStorage(const std::vector &uniforms) = 0; + virtual void getUniformfv(GLint location, GLfloat *params) = 0; + virtual void getUniformiv(GLint location, GLint *params) = 0; + virtual void getUniformuiv(GLint location, GLuint *params) = 0; - virtual void reset() = 0; + virtual void reset(); + + // TODO: The following functions are possibly only applicable to D3D backends. The should be carefully evaluated to + // determine if they can be removed from this interface. + virtual GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const = 0; + virtual GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const = 0; + virtual GLint getUsedSamplerRange(gl::SamplerType type) const = 0; + virtual void updateSamplerMapping() = 0; + virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0; + + virtual gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) = 0; + + virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) = 0; + virtual bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) = 0; + + virtual gl::Error applyUniforms() = 0; + virtual gl::Error applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps) = 0; + virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) = 0; + + protected: + DISALLOW_COPY_AND_ASSIGN(ProgramImpl); + + std::vector mUniforms; + std::vector mUniformIndex; + std::vector mUniformBlocks; + std::vector mTransformFeedbackLinkedVaryings; + + sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS]; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp new file mode 100644 index 0000000000..857fdc9dae --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.cpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderTarget.cpp: Implements serial handling for rx::RenderTarget + +#include "libGLESv2/renderer/RenderTarget.h" + +namespace rx +{ +unsigned int RenderTarget::mCurrentSerial = 1; + +RenderTarget::RenderTarget() + : mSerial(issueSerials(1)) +{ +} + +RenderTarget::~RenderTarget() +{ +} + +unsigned int RenderTarget::getSerial() const +{ + return mSerial; +} + +unsigned int RenderTarget::issueSerials(unsigned int count) +{ + unsigned int firstSerial = mCurrentSerial; + mCurrentSerial += count; + return firstSerial; +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h index 44637ec7de..3bdfb0cc98 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/RenderTarget.h @@ -18,28 +18,22 @@ namespace rx class RenderTarget { public: - RenderTarget() - { - mWidth = 0; - mHeight = 0; - mDepth = 0; - mInternalFormat = GL_NONE; - mActualFormat = GL_NONE; - mSamples = 0; - } + RenderTarget(); + virtual ~RenderTarget(); - virtual ~RenderTarget() {}; - - GLsizei getWidth() const { return mWidth; } - GLsizei getHeight() const { return mHeight; } - GLsizei getDepth() const { return mDepth; } - GLenum getInternalFormat() const { return mInternalFormat; } - GLenum getActualFormat() const { return mActualFormat; } - GLsizei getSamples() const { return mSamples; } - gl::Extents getExtents() const { return gl::Extents(mWidth, mHeight, mDepth); } + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLsizei getDepth() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLenum getActualFormat() const = 0; + virtual GLsizei getSamples() const = 0; + gl::Extents getExtents() const { return gl::Extents(getWidth(), getHeight(), getDepth()); } virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) = 0; + virtual unsigned int getSerial() const; + static unsigned int issueSerials(unsigned int count); + struct Desc { GLsizei width; GLsizei height; @@ -47,16 +41,11 @@ class RenderTarget GLenum format; }; - protected: - GLsizei mWidth; - GLsizei mHeight; - GLsizei mDepth; - GLenum mInternalFormat; - GLenum mActualFormat; - GLsizei mSamples; - private: DISALLOW_COPY_AND_ASSIGN(RenderTarget); + + const unsigned int mSerial; + static unsigned int mCurrentSerial; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp new file mode 100644 index 0000000000..770ae8e9c6 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.cpp @@ -0,0 +1,21 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferImpl.h: Implements the shared methods of the abstract class gl::RenderbufferImpl + +#include "libGLESv2/renderer/RenderbufferImpl.h" + +namespace rx +{ +RenderbufferImpl::RenderbufferImpl() +{ +} + +RenderbufferImpl::~RenderbufferImpl() +{ +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h new file mode 100644 index 0000000000..52e070f1d3 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/RenderbufferImpl.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferImpl.h: Defines the abstract class gl::RenderbufferImpl + +#ifndef LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ +#define LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ + +#include "angle_gl.h" + +#include "libGLESv2/Error.h" + +#include "common/angleutils.h" + +namespace rx +{ + +class RenderbufferImpl +{ + public: + RenderbufferImpl(); + virtual ~RenderbufferImpl() = 0; + + virtual gl::Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) = 0; + + virtual GLsizei getWidth() const = 0; + virtual GLsizei getHeight() const = 0; + virtual GLenum getInternalFormat() const = 0; + virtual GLenum getActualFormat() const = 0; + virtual GLsizei getSamples() const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferImpl); +}; + +} + +#endif // LIBGLESV2_RENDERER_RENDERBUFFERIMPL_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp index 910d0285f1..df3dae1e38 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp @@ -6,11 +6,12 @@ // Renderer.cpp: Implements EGL dependencies for creating and destroying Renderer instances. -#include "libGLESv2/main.h" -#include "libGLESv2/Program.h" -#include "libGLESv2/renderer/Renderer.h" #include "common/utilities.h" -#include "libGLESv2/Shader.h" +#include "libEGL/AttributeMap.h" +#include "libGLESv2/main.h" +#include "libGLESv2/renderer/Renderer.h" + +#include #if defined (ANGLE_ENABLE_D3D9) #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" @@ -29,15 +30,12 @@ #define ANGLE_DEFAULT_D3D11 0 #endif -#include - namespace rx { -Renderer::Renderer(egl::Display *display) - : mDisplay(display), - mCapsInitialized(false), - mCurrentClientVersion(2) +Renderer::Renderer() + : mCapsInitialized(false), + mWorkaroundsInitialized(false) { } @@ -78,12 +76,23 @@ const gl::Extensions &Renderer::getRendererExtensions() const return mExtensions; } -typedef Renderer *(*CreateRendererFunction)(egl::Display*, EGLNativeDisplayType, EGLint); +const Workarounds &Renderer::getWorkarounds() const +{ + if (!mWorkaroundsInitialized) + { + mWorkarounds = generateWorkarounds(); + mWorkaroundsInitialized = true; + } + + return mWorkarounds; +} + +typedef Renderer *(*CreateRendererFunction)(egl::Display*, EGLNativeDisplayType, const egl::AttributeMap &); template -Renderer *CreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType) +Renderer *CreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attributes) { - return new RendererType(display, nativeDisplay, requestedDisplayType); + return new RendererType(display, nativeDisplay, attributes); } } @@ -91,15 +100,16 @@ Renderer *CreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDispl extern "C" { -rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, EGLint requestedDisplayType) +rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativeDisplay, const egl::AttributeMap &attribMap) { std::vector rendererCreationFunctions; + EGLint requestedDisplayType = attribMap.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE); + # if defined(ANGLE_ENABLE_D3D11) if (nativeDisplay == EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE || nativeDisplay == EGL_D3D11_ONLY_DISPLAY_ANGLE || - requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE || - requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE) + requestedDisplayType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE) { rendererCreationFunctions.push_back(rx::CreateRenderer); } @@ -138,7 +148,7 @@ rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativ for (size_t i = 0; i < rendererCreationFunctions.size(); i++) { - rx::Renderer *renderer = rendererCreationFunctions[i](display, nativeDisplay, requestedDisplayType); + rx::Renderer *renderer = rendererCreationFunctions[i](display, nativeDisplay, attribMap); if (renderer->initialize() == EGL_SUCCESS) { return renderer; @@ -155,7 +165,8 @@ rx::Renderer *glCreateRenderer(egl::Display *display, EGLNativeDisplayType nativ void glDestroyRenderer(rx::Renderer *renderer) { - delete renderer; + ASSERT(renderer); + SafeDelete(renderer); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h index b2249741ab..b85895a938 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h @@ -10,10 +10,13 @@ #ifndef LIBGLESV2_RENDERER_RENDERER_H_ #define LIBGLESV2_RENDERER_RENDERER_H_ -#include "libGLESv2/Uniform.h" -#include "libGLESv2/angletypes.h" #include "libGLESv2/Caps.h" #include "libGLESv2/Error.h" +#include "libGLESv2/Uniform.h" +#include "libGLESv2/angletypes.h" +#include "libGLESv2/renderer/Workarounds.h" +#include "common/NativeWindow.h" +#include "common/mathutil.h" #include @@ -32,37 +35,26 @@ class Display; namespace gl { -class InfoLog; -class ProgramBinary; -struct LinkedVarying; -struct VertexAttribute; class Buffer; -class Texture; class Framebuffer; -struct VertexAttribCurrentValueData; +struct Data; } namespace rx { -class TextureStorage; -class VertexBuffer; -class IndexBuffer; class QueryImpl; -class FenceImpl; +class FenceNVImpl; +class FenceSyncImpl; class BufferImpl; class VertexArrayImpl; -class BufferStorage; -struct TranslatedIndexData; class ShaderImpl; class ProgramImpl; -class ShaderExecutable; -class SwapChain; -class RenderTarget; -class Image; -class TextureStorage; -class UniformStorage; class TextureImpl; class TransformFeedbackImpl; +class RenderbufferImpl; +struct TranslatedIndexData; +struct Workarounds; +class SwapChain; struct ConfigDesc { @@ -73,6 +65,110 @@ struct ConfigDesc bool es3Capable; }; +class Renderer +{ + public: + Renderer(); + virtual ~Renderer(); + + virtual EGLint initialize() = 0; + virtual bool resetDevice() = 0; + + virtual int generateConfigs(ConfigDesc **configDescList) = 0; + virtual void deleteConfigs(ConfigDesc *configDescList) = 0; + + virtual gl::Error sync(bool block) = 0; + + virtual gl::Error drawArrays(const gl::Data &data, GLenum mode, + GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error drawElements(const gl::Data &data, GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) = 0; + + virtual gl::Error clear(const gl::Data &data, GLbitfield mask) = 0; + virtual gl::Error clearBufferfv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLfloat *values) = 0; + virtual gl::Error clearBufferuiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLuint *values) = 0; + virtual gl::Error clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values) = 0; + virtual gl::Error clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) = 0; + + virtual gl::Error readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) = 0; + + virtual gl::Error blitFramebuffer(const gl::Data &data, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) = 0; + + // TODO(jmadill): caps? and virtual for egl::Display + virtual bool getShareHandleSupport() const = 0; + virtual bool getPostSubBufferSupport() const = 0; + + // Shader creation + virtual ShaderImpl *createShader(const gl::Data &data, GLenum type) = 0; + virtual ProgramImpl *createProgram() = 0; + + // Shader operations + virtual void releaseShaderCompiler() = 0; + + // Texture creation + virtual TextureImpl *createTexture(GLenum target) = 0; + + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer() = 0; + virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth) = 0; + + // Buffer creation + virtual BufferImpl *createBuffer() = 0; + + // Vertex Array creation + virtual VertexArrayImpl *createVertexArray() = 0; + + // Query and Fence creation + virtual QueryImpl *createQuery(GLenum type) = 0; + virtual FenceNVImpl *createFenceNV() = 0; + virtual FenceSyncImpl *createFenceSync() = 0; + + // Transform Feedback creation + virtual TransformFeedbackImpl *createTransformFeedback() = 0; + + // lost device + //TODO(jmadill): investigate if this stuff is necessary in GL + virtual void notifyDeviceLost() = 0; + virtual bool isDeviceLost() = 0; + virtual bool testDeviceLost(bool notify) = 0; + virtual bool testDeviceResettable() = 0; + + virtual DWORD getAdapterVendor() const = 0; + virtual std::string getRendererDescription() const = 0; + virtual GUID getAdapterIdentifier() const = 0; + + // Renderer capabilities (virtual because of egl::Display) + virtual const gl::Caps &getRendererCaps() const; + const gl::TextureCapsMap &getRendererTextureCaps() const; + virtual const gl::Extensions &getRendererExtensions() const; + const Workarounds &getWorkarounds() const; + + // TODO(jmadill): needed by egl::Display, probably should be removed + virtual int getMajorShaderModel() const = 0; + virtual int getMinSwapInterval() const = 0; + virtual int getMaxSwapInterval() const = 0; + virtual bool getLUID(LUID *adapterLuid) const = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Renderer); + + virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; + virtual Workarounds generateWorkarounds() const = 0; + + mutable bool mCapsInitialized; + mutable gl::Caps mCaps; + mutable gl::TextureCapsMap mTextureCaps; + mutable gl::Extensions mExtensions; + + mutable bool mWorkaroundsInitialized; + mutable Workarounds mWorkarounds; +}; + struct dx_VertexConstants { float depthRange[4]; @@ -93,176 +189,5 @@ enum ShaderType SHADER_GEOMETRY }; -class Renderer -{ - public: - explicit Renderer(egl::Display *display); - virtual ~Renderer(); - - virtual EGLint initialize() = 0; - virtual bool resetDevice() = 0; - - virtual int generateConfigs(ConfigDesc **configDescList) = 0; - virtual void deleteConfigs(ConfigDesc *configDescList) = 0; - - virtual void sync(bool block) = 0; - - virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; - - virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; - virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler) = 0; - virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; - - virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0; - - virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0; - virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask) = 0; - virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, - int stencilBackRef, bool frontFaceCCW) = 0; - - virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0; - virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, - bool ignoreViewport) = 0; - - virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer) = 0; - virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, - bool rasterizerDiscard, bool transformFeedbackActive) = 0; - virtual gl::Error applyUniforms(const gl::ProgramBinary &programBinary) = 0; - virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0; - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) = 0; - virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) = 0; - - virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; - virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, - gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; - - virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0; - - virtual void markAllStateDirty() = 0; - - // lost device - virtual void notifyDeviceLost() = 0; - virtual bool isDeviceLost() = 0; - virtual bool testDeviceLost(bool notify) = 0; - virtual bool testDeviceResettable() = 0; - - // Renderer capabilities (virtual because it is used by egl::Display, do not override) - virtual const gl::Caps &getRendererCaps() const; - virtual const gl::TextureCapsMap &getRendererTextureCaps() const; - virtual const gl::Extensions &getRendererExtensions() const; - - virtual DWORD getAdapterVendor() const = 0; - virtual std::string getRendererDescription() const = 0; - virtual GUID getAdapterIdentifier() const = 0; - - virtual unsigned int getReservedVertexUniformVectors() const = 0; - virtual unsigned int getReservedFragmentUniformVectors() const = 0; - virtual unsigned int getReservedVertexUniformBuffers() const = 0; - virtual unsigned int getReservedFragmentUniformBuffers() const = 0; - virtual bool getShareHandleSupport() const = 0; - virtual bool getPostSubBufferSupport() const = 0; - - virtual int getMajorShaderModel() const = 0; - virtual int getMinSwapInterval() const = 0; - virtual int getMaxSwapInterval() const = 0; - - // Pixel operations - virtual bool copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source) = 0; - virtual bool copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source) = 0; - virtual bool copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source) = 0; - virtual bool copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source) = 0; - - virtual bool copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) = 0; - virtual bool copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) = 0; - virtual bool copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; - virtual bool copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; - - virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) = 0; - - virtual gl::Error readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, - GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) = 0; - - // RenderTarget creation - virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth) = 0; - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples) = 0; - - // Shader creation - virtual ShaderImpl *createShader(GLenum type) = 0; - virtual ProgramImpl *createProgram() = 0; - - // Shader operations - virtual void releaseShaderCompiler() = 0; - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers) = 0; - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) = 0; - virtual UniformStorage *createUniformStorage(size_t storageSize) = 0; - - // Image operations - virtual Image *createImage() = 0; - virtual void generateMipmap(Image *dest, Image *source) = 0; - virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0; - virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0; - virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0; - virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; - virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; - - // Texture creation - virtual TextureImpl *createTexture(GLenum target) = 0; - - // Buffer creation - virtual BufferImpl *createBuffer() = 0; - virtual VertexBuffer *createVertexBuffer() = 0; - virtual IndexBuffer *createIndexBuffer() = 0; - - // Vertex Array creation - virtual VertexArrayImpl *createVertexArray() = 0; - - // Query and Fence creation - virtual QueryImpl *createQuery(GLenum type) = 0; - virtual FenceImpl *createFence() = 0; - - // Transform Feedback creation - virtual TransformFeedbackImpl* createTransformFeedback() = 0; - - // Current GLES client version - void setCurrentClientVersion(int clientVersion) { mCurrentClientVersion = clientVersion; } - int getCurrentClientVersion() const { return mCurrentClientVersion; } - - // Buffer-to-texture and Texture-to-buffer copies - virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; - virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; - - virtual bool getLUID(LUID *adapterLuid) const = 0; - virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; - virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; - - protected: - egl::Display *mDisplay; - - private: - DISALLOW_COPY_AND_ASSIGN(Renderer); - - virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap* outTextureCaps, gl::Extensions *outExtensions) const = 0; - - mutable bool mCapsInitialized; - mutable gl::Caps mCaps; - mutable gl::TextureCapsMap mTextureCaps; - mutable gl::Extensions mExtensions; - - int mCurrentClientVersion; -}; - } #endif // LIBGLESV2_RENDERER_RENDERER_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h index f17195673d..f1a96d74fb 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderExecutable.h @@ -40,10 +40,21 @@ class ShaderExecutable return mFunctionBuffer.size(); } + const std::string &getDebugInfo() const + { + return mDebugInfo; + } + + void appendDebugInfo(const std::string &info) + { + mDebugInfo += info; + } + private: DISALLOW_COPY_AND_ASSIGN(ShaderExecutable); std::vector mFunctionBuffer; + std::string mDebugInfo; }; class UniformStorage @@ -64,4 +75,4 @@ class UniformStorage } -#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE9_H_ +#endif // LIBGLESV2_RENDERER_SHADEREXECUTABLE_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h index de5d30e6fe..cb0d360f0b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/ShaderImpl.h @@ -23,9 +23,10 @@ class ShaderImpl ShaderImpl() { } virtual ~ShaderImpl() { } - virtual bool compile(const std::string &source) = 0; + virtual bool compile(const gl::Data &data, const std::string &source) = 0; virtual const std::string &getInfoLog() const = 0; virtual const std::string &getTranslatedSource() const = 0; + virtual std::string getDebugInfo() const = 0; const std::vector &getVaryings() const { return mVaryings; } const std::vector &getUniforms() const { return mUniforms; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h index 1ec702f299..1417e0bdf6 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h @@ -11,28 +11,24 @@ #define LIBGLESV2_RENDERER_SWAPCHAIN_H_ #include "common/angleutils.h" +#include "common/NativeWindow.h" #include "common/platform.h" #include #include -#include + +#if !defined(ANGLE_FORCE_VSYNC_OFF) +#define ANGLE_FORCE_VSYNC_OFF 0 +#endif namespace rx { -enum SwapFlags -{ - SWAP_NORMAL = 0, - SWAP_ROTATE_90 = 1, - SWAP_ROTATE_270 = 2, - SWAP_ROTATE_180 = SWAP_ROTATE_90|SWAP_ROTATE_270, -}; - class SwapChain { public: - SwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mWindow(window), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) + SwapChain(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) + : mNativeWindow(nativeWindow), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) { } @@ -40,13 +36,16 @@ class SwapChain virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) = 0; + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; virtual void recreate() = 0; + GLenum GetBackBufferInternalFormat() const { return mBackBufferFormat; } + GLenum GetDepthBufferInternalFormat() const { return mDepthBufferFormat; } + virtual HANDLE getShareHandle() {return mShareHandle;}; protected: - const EGLNativeWindowType mWindow; // Window that the surface is created for. + rx::NativeWindow mNativeWindow; // Handler for the Window that the surface is created for. const GLenum mBackBufferFormat; const GLenum mDepthBufferFormat; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h b/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h index e3cc50d680..3e662557e4 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/TextureImpl.h @@ -10,6 +10,7 @@ #define LIBGLESV2_RENDERER_TEXTUREIMPL_H_ #include "common/angleutils.h" +#include "libGLESv2/Error.h" #include "angle_gl.h" @@ -31,19 +32,12 @@ namespace rx { class Image; -class Renderer; -class TextureStorage; class TextureImpl { public: virtual ~TextureImpl() {}; - // TODO: If this methods could go away that would be ideal; - // TextureStorage should only be necessary for the D3D backend, and as such - // higher level code should not rely on it. - virtual TextureStorage *getNativeTexture() = 0; - // Deprecated in favour of the ImageIndex method virtual Image *getImage(int level, int layer) const = 0; virtual Image *getImage(const gl::ImageIndex &index) const = 0; @@ -51,15 +45,15 @@ class TextureImpl virtual void setUsage(GLenum usage) = 0; - virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) = 0; - virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; - virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) = 0; - virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; - virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0; + virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) = 0; + virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0; + virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) = 0; - virtual void generateMipmaps() = 0; + virtual gl::Error generateMipmaps() = 0; virtual void bindTexImage(egl::Surface *surface) = 0; virtual void releaseTexImage() = 0; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h b/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h new file mode 100644 index 0000000000..20a166fb7a --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/Workarounds.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// angletypes.h: Workarounds for driver bugs and other issues. + +#ifndef LIBGLESV2_RENDERER_WORKAROUNDS_H_ +#define LIBGLESV2_RENDERER_WORKAROUNDS_H_ + +// TODO(jmadill,zmo,geofflang): make a workarounds library that can operate +// independent of ANGLE's renderer. Workarounds should also be accessible +// outside of the Renderer. + +namespace rx +{ + +enum D3DWorkaroundType +{ + ANGLE_D3D_WORKAROUND_NONE, + ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION, + ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION +}; + +struct Workarounds +{ + Workarounds() + : mrtPerfWorkaround(false), + setDataFasterThanImageUpload(false) + {} + + bool mrtPerfWorkaround; + bool setDataFasterThanImageUpload; +}; + +} + +#endif // LIBGLESV2_RENDERER_WORKAROUNDS_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp index 004223d70f..aabc9f04e9 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.cpp @@ -6,7 +6,7 @@ // copyimage.cpp: Defines image copying functions -#include "libGLESv2/renderer/copyImage.h" +#include "libGLESv2/renderer/copyimage.h" namespace rx { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp index a34ef03fb8..dd0d3f52ad 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.cpp @@ -9,7 +9,6 @@ #include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/renderer/d3d/VertexBuffer.h" #include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/main.h" namespace rx @@ -37,6 +36,13 @@ BufferD3D *BufferD3D::makeBufferD3D(BufferImpl *buffer) return static_cast(buffer); } +BufferD3D *BufferD3D::makeFromBuffer(gl::Buffer *buffer) +{ + BufferImpl *impl = buffer->getImplementation(); + ASSERT(impl); + return makeBufferD3D(impl); +} + void BufferD3D::updateSerial() { mSerial = mNextSerial++; @@ -46,11 +52,11 @@ void BufferD3D::initializeStaticData() { if (!mStaticVertexBuffer) { - mStaticVertexBuffer = new rx::StaticVertexBufferInterface(getRenderer()); + mStaticVertexBuffer = new StaticVertexBufferInterface(getRenderer()); } if (!mStaticIndexBuffer) { - mStaticIndexBuffer = new rx::StaticIndexBufferInterface(getRenderer()); + mStaticIndexBuffer = new StaticIndexBufferInterface(getRenderer()); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h index 44f14cee58..1a1308c545 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/BufferD3D.h @@ -12,10 +12,11 @@ #include "libGLESv2/renderer/BufferImpl.h" #include "libGLESv2/angletypes.h" +#include + namespace rx { - -class Renderer; +class RendererD3D; class StaticIndexBufferInterface; class StaticVertexBufferInterface; @@ -26,15 +27,17 @@ class BufferD3D : public BufferImpl virtual ~BufferD3D(); static BufferD3D *makeBufferD3D(BufferImpl *buffer); + static BufferD3D *makeFromBuffer(gl::Buffer *buffer); unsigned int getSerial() const { return mSerial; } + virtual gl::Error getData(const uint8_t **outData) = 0; virtual size_t getSize() const = 0; virtual bool supportsDirectBinding() const = 0; - virtual Renderer* getRenderer() = 0; + virtual RendererD3D *getRenderer() = 0; - rx::StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } - rx::StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } + StaticVertexBufferInterface *getStaticVertexBuffer() { return mStaticVertexBuffer; } + StaticIndexBufferInterface *getStaticIndexBuffer() { return mStaticIndexBuffer; } void initializeStaticData(); void invalidateStaticData(); @@ -46,8 +49,8 @@ class BufferD3D : public BufferImpl void updateSerial(); - rx::StaticVertexBufferInterface *mStaticVertexBuffer; - rx::StaticIndexBufferInterface *mStaticIndexBuffer; + StaticVertexBufferInterface *mStaticVertexBuffer; + StaticIndexBufferInterface *mStaticIndexBuffer; unsigned int mUnmodifiedDataUse; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp index 13411ebe64..3d5bfe0cbe 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp @@ -8,10 +8,10 @@ #include "libGLESv2/renderer/d3d/DynamicHLSL.h" #include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/Shader.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/Program.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/Shader.h" #include "libGLESv2/formatutils.h" #include "common/utilities.h" @@ -22,6 +22,9 @@ META_ASSERT(GL_INVALID_INDEX == UINT_MAX); using namespace gl; +namespace rx +{ + namespace { @@ -70,7 +73,7 @@ std::string HLSLTypeString(GLenum type) return HLSLComponentTypeString(gl::VariableComponentType(type), gl::VariableComponentCount(type)); } -const rx::PixelShaderOutputVariable &GetOutputAtLocation(const std::vector &outputVariables, +const PixelShaderOutputVariable &GetOutputAtLocation(const std::vector &outputVariables, unsigned int location) { for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex) @@ -85,15 +88,12 @@ const rx::PixelShaderOutputVariable &GetOutputAtLocation(const std::vector& transformFeedbackVaryings) +int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector &transformFeedbackVaryings) { // TODO (geofflang): Use context's caps const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors; @@ -262,6 +262,13 @@ int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, rx::Shad for (unsigned int feedbackVaryingIndex = 0; feedbackVaryingIndex < transformFeedbackVaryings.size(); feedbackVaryingIndex++) { const std::string &transformFeedbackVarying = transformFeedbackVaryings[feedbackVaryingIndex]; + + if (transformFeedbackVarying == "gl_Position" || transformFeedbackVarying == "gl_PointSize") + { + // do not pack builtin XFB varyings + continue; + } + if (packedVaryings.find(transformFeedbackVarying) == packedVaryings.end()) { bool found = false; @@ -281,7 +288,7 @@ int DynamicHLSL::packVaryings(InfoLog &infoLog, VaryingPacking packing, rx::Shad } } - if (!found && transformFeedbackVarying != "gl_Position" && transformFeedbackVarying != "gl_PointSize") + if (!found) { infoLog.append("Transform feedback varying %s does not exist in the vertex shader.", transformFeedbackVarying.c_str()); return -1; @@ -400,7 +407,7 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout(const std::string &s // data reinterpretation (eg for pure integer->float, float->pure integer) // TODO: issue warning with gl debug info extension, when supported if (IsMatrixType(shaderAttribute.type) || - (mRenderer->getVertexConversionType(vertexFormat) & rx::VERTEX_CONVERT_GPU) != 0) + (mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0) { initHLSL += generateAttributeConversionHLSL(vertexFormat, shaderAttribute); } @@ -639,7 +646,7 @@ void DynamicHLSL::storeBuiltinLinkedVaryings(const SemanticInfo &info, } } -void DynamicHLSL::storeUserLinkedVaryings(const rx::ShaderD3D *vertexShader, +void DynamicHLSL::storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector *linkedVaryings) const { const std::string &varyingSemantic = getVaryingSemantic(vertexShader->mUsesPointSize); @@ -662,10 +669,11 @@ void DynamicHLSL::storeUserLinkedVaryings(const rx::ShaderD3D *vertexShader, } } -bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const VaryingPacking packing, - std::string& pixelHLSL, std::string& vertexHLSL, - rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader, - const std::vector& transformFeedbackVaryings, +bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data, InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, std::vector *linkedVaryings, std::map *programOutputVars, std::vector *outPixelShaderKey, @@ -691,21 +699,17 @@ bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const // Write the HLSL input/output declarations const int shaderModel = mRenderer->getMajorShaderModel(); - - // TODO (geofflang): Use context's caps - const int maxVaryingVectors = mRenderer->getRendererCaps().maxVaryingVectors; - const int registersNeeded = registers + (usesFragCoord ? 1 : 0) + (usesPointCoord ? 1 : 0); // Two cases when writing to gl_FragColor and using ESSL 1.0: // - with a 3.0 context, the output color is copied to channel 0 // - with a 2.0 context, the output color is broadcast to all channels - const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3); - const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getRendererCaps().maxDrawBuffers : 1); + const bool broadcast = (fragmentShader->mUsesFragColor && data.clientVersion < 3); + const unsigned int numRenderTargets = (broadcast || usesMRT ? data.caps->maxDrawBuffers : 1); int shaderVersion = vertexShader->getShaderVersion(); - if (registersNeeded > maxVaryingVectors) + if (static_cast(registersNeeded) > data.caps->maxVaryingVectors) { infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord"); return false; @@ -772,7 +776,7 @@ bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const for (int row = 0; row < variableRows; row++) { - int r = varying.registerIndex + varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors + elementIndex * variableRows + row; + int r = varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row; vertexHLSL += " output.v" + Str(r); vertexHLSL += " = _" + varying.name; @@ -920,7 +924,7 @@ bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType)); for (int row = 0; row < variableRows; row++) { - std::string n = Str(varying.registerIndex + varying.columnIndex * mRenderer->getRendererCaps().maxVaryingVectors + elementIndex * variableRows + row); + std::string n = Str(varying.registerIndex + varying.columnIndex * data.caps->maxVaryingVectors + elementIndex * variableRows + row); pixelHLSL += " _" + varying.name; if (varying.isArray()) @@ -966,7 +970,7 @@ bool DynamicHLSL::generateShaderLinkHLSL(InfoLog &infoLog, int registers, const return true; } -void DynamicHLSL::defineOutputVariables(rx::ShaderD3D *fragmentShader, std::map *programOutputVars) const +void DynamicHLSL::defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const { const std::vector &shaderOutputVars = fragmentShader->getActiveOutputVariables(); @@ -994,14 +998,14 @@ void DynamicHLSL::defineOutputVariables(rx::ShaderD3D *fragmentShader, std::map< } } -std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader) const +std::string DynamicHLSL::generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const { // for now we only handle point sprite emulation ASSERT(vertexShader->mUsesPointSize && mRenderer->getMajorShaderModel() >= 4); return generatePointSpriteHLSL(registers, fragmentShader, vertexShader); } -std::string DynamicHLSL::generatePointSpriteHLSL(int registers, rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader) const +std::string DynamicHLSL::generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const { ASSERT(registers >= 0); ASSERT(vertexShader->mUsesPointSize); @@ -1047,7 +1051,7 @@ std::string DynamicHLSL::generatePointSpriteHLSL(int registers, rx::ShaderD3D *f "void main(point GS_INPUT input[1], inout TriangleStream outStream)\n" "{\n" " GS_OUTPUT output = (GS_OUTPUT)0;\n" - " output.gl_Position = input[0].gl_Position;\n"; + " output.gl_Position = input[0].gl_Position;\n" " output.gl_PointSize = input[0].gl_PointSize;\n"; for (int r = 0; r < registers; r++) @@ -1135,7 +1139,7 @@ void DynamicHLSL::getInputLayoutSignature(const VertexFormat inputLayout[], GLen } else { - bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & rx::VERTEX_CONVERT_GPU) != 0); + bool gpuConverted = ((mRenderer->getVertexConversionType(vertexFormat) & VERTEX_CONVERT_GPU) != 0); signature[inputIndex] = (gpuConverted ? GL_TRUE : GL_FALSE); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h index f68ed98401..c46bbf6ce0 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/DynamicHLSL.h @@ -10,18 +10,13 @@ #define LIBGLESV2_RENDERER_DYNAMIC_HLSL_H_ #include "common/angleutils.h" -#include "libGLESv2/constants.h" +#include "libGLESv2/Constants.h" #include "angle_gl.h" #include #include -namespace rx -{ -class Renderer; -} - namespace sh { struct Attribute; @@ -36,11 +31,12 @@ struct LinkedVarying; struct VertexAttribute; struct VertexFormat; struct PackedVarying; +struct Data; } namespace rx { -class Renderer; +class RendererD3D; class ShaderD3D; typedef const gl::PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4]; @@ -56,30 +52,31 @@ struct PixelShaderOutputVariable class DynamicHLSL { public: - explicit DynamicHLSL(rx::Renderer *const renderer); + explicit DynamicHLSL(RendererD3D *const renderer); - int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, rx::ShaderD3D *fragmentShader, - rx::ShaderD3D *vertexShader, const std::vector& transformFeedbackVaryings); + int packVaryings(gl::InfoLog &infoLog, VaryingPacking packing, ShaderD3D *fragmentShader, + ShaderD3D *vertexShader, const std::vector& transformFeedbackVaryings); std::string generateVertexShaderForInputLayout(const std::string &sourceShader, const gl::VertexFormat inputLayout[], const sh::Attribute shaderAttributes[]) const; std::string generatePixelShaderForOutputSignature(const std::string &sourceShader, const std::vector &outputVariables, bool usesFragDepth, const std::vector &outputLayout) const; - bool generateShaderLinkHLSL(gl::InfoLog &infoLog, int registers, const VaryingPacking packing, - std::string& pixelHLSL, std::string& vertexHLSL, - rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader, - const std::vector& transformFeedbackVaryings, + bool generateShaderLinkHLSL(const gl::Data &data, gl::InfoLog &infoLog, int registers, + const VaryingPacking packing, + std::string &pixelHLSL, std::string &vertexHLSL, + ShaderD3D *fragmentShader, ShaderD3D *vertexShader, + const std::vector &transformFeedbackVaryings, std::vector *linkedVaryings, std::map *programOutputVars, std::vector *outPixelShaderKey, bool *outUsesFragDepth) const; - std::string generateGeometryShaderHLSL(int registers, rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader) const; + std::string generateGeometryShaderHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; private: DISALLOW_COPY_AND_ASSIGN(DynamicHLSL); - rx::Renderer *const mRenderer; + RendererD3D *const mRenderer; struct SemanticInfo; @@ -88,10 +85,10 @@ class DynamicHLSL bool pixelShader) const; std::string generateVaryingLinkHLSL(const SemanticInfo &info, const std::string &varyingHLSL) const; std::string generateVaryingHLSL(const ShaderD3D *shader) const; - void storeUserLinkedVaryings(const rx::ShaderD3D *vertexShader, std::vector *linkedVaryings) const; + void storeUserLinkedVaryings(const ShaderD3D *vertexShader, std::vector *linkedVaryings) const; void storeBuiltinLinkedVaryings(const SemanticInfo &info, std::vector *linkedVaryings) const; - void defineOutputVariables(rx::ShaderD3D *fragmentShader, std::map *programOutputVars) const; - std::string generatePointSpriteHLSL(int registers, rx::ShaderD3D *fragmentShader, rx::ShaderD3D *vertexShader) const; + void defineOutputVariables(ShaderD3D *fragmentShader, std::map *programOutputVars) const; + std::string generatePointSpriteHLSL(int registers, ShaderD3D *fragmentShader, ShaderD3D *vertexShader) const; // Prepend an underscore static std::string decorateVariable(const std::string &name); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp index d0131974ee..776d92b202 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp @@ -8,34 +8,116 @@ #include "libGLESv2/Program.h" #include "libGLESv2/main.h" +#include "common/features.h" #include "common/utilities.h" -#include "common/platform.h" - -#if defined(__MINGW32__) && !defined(D3DCOMPILER_DLL) - -// Add define + typedefs for older MinGW-w64 headers (pre 5783) - -#define D3DCOMPILER_DLL L"d3dcompiler_43.dll" - -HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, - const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, - const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); -typedef HRESULT (WINAPI *pD3DCompile)(const void *data, SIZE_T data_size, const char *filename, - const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, - const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); - -#endif // __MINGW32__ && !D3DCOMPILER_DLL #ifndef QT_D3DCOMPILER_DLL #define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL #endif +#ifndef D3DCOMPILE_RESERVED16 +#define D3DCOMPILE_RESERVED16 (1 << 16) +#endif +#ifndef D3DCOMPILE_RESERVED17 +#define D3DCOMPILE_RESERVED17 (1 << 17) +#endif + +// Definitions local to the translation unit +namespace +{ + +#ifdef CREATE_COMPILER_FLAG_INFO + #undef CREATE_COMPILER_FLAG_INFO +#endif + +#define CREATE_COMPILER_FLAG_INFO(flag) { flag, #flag } + +struct CompilerFlagInfo +{ + UINT mFlag; + const char *mName; +}; + +CompilerFlagInfo CompilerFlagInfos[] = +{ + // NOTE: The data below is copied from d3dcompiler.h + // If something changes there it should be changed here as well + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_DEBUG), // (1 << 0) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_VALIDATION), // (1 << 1) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_SKIP_OPTIMIZATION), // (1 << 2) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR), // (1 << 3) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR), // (1 << 4) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PARTIAL_PRECISION), // (1 << 5) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT), // (1 << 6) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT), // (1 << 7) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_NO_PRESHADER), // (1 << 8) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_AVOID_FLOW_CONTROL), // (1 << 9) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_PREFER_FLOW_CONTROL), // (1 << 10) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_STRICTNESS), // (1 << 11) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY), // (1 << 12) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_IEEE_STRICTNESS), // (1 << 13) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL0), // (1 << 14) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL1), // 0 + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL2), // ((1 << 14) | (1 << 15)) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_OPTIMIZATION_LEVEL3), // (1 << 15) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED16), // (1 << 16) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_RESERVED17), // (1 << 17) + CREATE_COMPILER_FLAG_INFO(D3DCOMPILE_WARNINGS_ARE_ERRORS) // (1 << 18) +}; + +#undef CREATE_COMPILER_FLAG_INFO + +bool IsCompilerFlagSet(UINT mask, UINT flag) +{ + bool isFlagSet = IsMaskFlagSet(mask, flag); + + switch(flag) + { + case D3DCOMPILE_OPTIMIZATION_LEVEL0: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL3)); + + case D3DCOMPILE_OPTIMIZATION_LEVEL1: + return (mask & D3DCOMPILE_OPTIMIZATION_LEVEL2) == UINT(0); + + case D3DCOMPILE_OPTIMIZATION_LEVEL3: + return isFlagSet && !IsMaskFlagSet(mask, UINT(D3DCOMPILE_OPTIMIZATION_LEVEL0)); + + default: + return isFlagSet; + } +} + +const char *GetCompilerFlagName(UINT mask, size_t flagIx) +{ + const CompilerFlagInfo &flagInfo = CompilerFlagInfos[flagIx]; + if (IsCompilerFlagSet(mask, flagInfo.mFlag)) + { + return flagInfo.mName; + } + + return nullptr; +} + +} namespace rx { +CompileConfig::CompileConfig() + : flags(0), + name() +{ +} + +CompileConfig::CompileConfig(UINT flags, const std::string &name) + : flags(flags), + name(name) +{ +} + HLSLCompiler::HLSLCompiler() : mD3DCompilerModule(NULL), - mD3DCompileFunc(NULL) + mD3DCompileFunc(NULL), + mD3DDisassembleFunc(NULL) { } @@ -46,7 +128,7 @@ HLSLCompiler::~HLSLCompiler() bool HLSLCompiler::initialize() { -#if !defined(ANGLE_PLATFORM_WINRT) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; @@ -83,17 +165,32 @@ bool HLSLCompiler::initialize() break; } + if (!mD3DCompilerModule) + { + // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. + mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL); + } + if (!mD3DCompilerModule) { ERR("No D3D compiler module found - aborting!\n"); return false; } - mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); + mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); ASSERT(mD3DCompileFunc); + + mD3DDisassembleFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DDisassemble")); + ASSERT(mD3DDisassembleFunc); + #else - mD3DCompileFunc = reinterpret_cast(&D3DCompile); + // D3D Shader compiler is linked already into this module, so the export + // can be directly assigned. + mD3DCompilerModule = NULL; + mD3DCompileFunc = reinterpret_cast(D3DCompile); + mD3DDisassembleFunc = reinterpret_cast(D3DDisassemble); #endif + return mD3DCompileFunc != NULL; } @@ -104,61 +201,133 @@ void HLSLCompiler::release() FreeLibrary(mD3DCompilerModule); mD3DCompilerModule = NULL; mD3DCompileFunc = NULL; + mD3DDisassembleFunc = NULL; } } -ShaderBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, - const UINT optimizationFlags[], const char *flagNames[], int attempts) const +gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const { -#if !defined(ANGLE_PLATFORM_WINRT) - ASSERT(mD3DCompilerModule && mD3DCompileFunc); +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + ASSERT(mD3DCompilerModule); +#endif + ASSERT(mD3DCompileFunc); + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + if (gl::perfActive()) + { + std::string sourcePath = getTempPath(); + std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str()); + writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); + } #endif - if (!hlsl) - { - return NULL; - } + const D3D_SHADER_MACRO *macros = overrideMacros ? overrideMacros : NULL; - pD3DCompile compileFunc = reinterpret_cast(mD3DCompileFunc); - for (int i = 0; i < attempts; ++i) + for (size_t i = 0; i < configs.size(); ++i) { ID3DBlob *errorMessage = NULL; ID3DBlob *binary = NULL; - HRESULT result = compileFunc(hlsl, strlen(hlsl), gl::g_fakepath, NULL, NULL, "main", profile, optimizationFlags[i], 0, &binary, &errorMessage); + HRESULT result = mD3DCompileFunc(hlsl.c_str(), hlsl.length(), gl::g_fakepath, macros, NULL, "main", profile.c_str(), + configs[i].flags, 0, &binary, &errorMessage); if (errorMessage) { - const char *message = (const char*)errorMessage->GetBufferPointer(); - - infoLog.appendSanitized(message); - TRACE("\n%s", hlsl); - TRACE("\n%s", message); - + std::string message = reinterpret_cast(errorMessage->GetBufferPointer()); SafeRelease(errorMessage); + + infoLog.appendSanitized(message.c_str()); + TRACE("\n%s", hlsl.c_str()); + TRACE("\n%s", message.c_str()); + + if (message.find("error X3531:") != std::string::npos) // "can't unroll loops marked with loop attribute" + { + macros = NULL; // Disable [loop] and [flatten] + + // Retry without changing compiler flags + i--; + continue; + } } if (SUCCEEDED(result)) { - return (ShaderBlob*)binary; + *outCompiledBlob = binary; + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + (*outDebugInfo) += "// COMPILER INPUT HLSL BEGIN\n\n" + hlsl + "\n// COMPILER INPUT HLSL END\n"; + (*outDebugInfo) += "\n\n// ASSEMBLY BEGIN\n\n"; + (*outDebugInfo) += "// Compiler configuration: " + configs[i].name + "\n// Flags:\n"; + for (size_t fIx = 0; fIx < ArraySize(CompilerFlagInfos); ++fIx) + { + const char *flagName = GetCompilerFlagName(configs[i].flags, fIx); + if (flagName != nullptr) + { + (*outDebugInfo) += std::string("// ") + flagName + "\n"; + } + } + + (*outDebugInfo) += "// Macros:\n"; + if (macros == nullptr) + { + (*outDebugInfo) += "// - : -\n"; + } + else + { + for (const D3D_SHADER_MACRO *mIt = macros; mIt->Name != nullptr; ++mIt) + { + (*outDebugInfo) += std::string("// ") + mIt->Name + " : " + mIt->Definition + "\n"; + } + } + + (*outDebugInfo) += "\n" + disassembleBinary(binary) + "\n// ASSEMBLY END\n"; +#endif + + return gl::Error(GL_NO_ERROR); } else { if (result == E_OUTOFMEMORY) { - return gl::error(GL_OUT_OF_MEMORY, (ShaderBlob*)NULL); + *outCompiledBlob = NULL; + return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result); } - infoLog.append("Warning: D3D shader compilation failed with %s flags.", flagNames[i]); + infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str()); - if (i + 1 < attempts) + if (i + 1 < configs.size()) { - infoLog.append(" Retrying with %s.\n", flagNames[i + 1]); + infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str()); } } } - return NULL; + // None of the configurations succeeded in compiling this shader but the compiler is still intact + *outCompiledBlob = NULL; + return gl::Error(GL_NO_ERROR); +} + +std::string HLSLCompiler::disassembleBinary(ID3DBlob *shaderBinary) const +{ + // Retrieve disassembly + UINT flags = D3D_DISASM_ENABLE_DEFAULT_VALUE_PRINTS | D3D_DISASM_ENABLE_INSTRUCTION_NUMBERING; + ID3DBlob *disassembly = NULL; + pD3DDisassemble disassembleFunc = reinterpret_cast(mD3DDisassembleFunc); + LPCVOID buffer = shaderBinary->GetBufferPointer(); + SIZE_T bufSize = shaderBinary->GetBufferSize(); + HRESULT result = disassembleFunc(buffer, bufSize, flags, "", &disassembly); + + std::string asmSrc; + if (SUCCEEDED(result)) + { + asmSrc = reinterpret_cast(disassembly->GetBufferPointer()); + } + + SafeRelease(disassembly); + + return asmSrc; } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h index 0ce9e44be5..ff56f8035a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h @@ -1,7 +1,13 @@ #ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ #define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_ +#include "libGLESv2/Error.h" + #include "common/angleutils.h" +#include "common/platform.h" + +#include +#include namespace gl { @@ -11,8 +17,14 @@ class InfoLog; namespace rx { -typedef void* ShaderBlob; -typedef void(*CompileFuncPtr)(); +struct CompileConfig +{ + UINT flags; + std::string name; + + CompileConfig(); + CompileConfig(UINT flags, const std::string &name); +}; class HLSLCompiler { @@ -23,14 +35,20 @@ class HLSLCompiler bool initialize(); void release(); - ShaderBlob *compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, - const UINT optimizationFlags[], const char *flagNames[], int attempts) const; + // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob + // even if no GL errors are returned. + gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile, + const std::vector &configs, const D3D_SHADER_MACRO *overrideMacros, + ID3DBlob **outCompiledBlob, std::string *outDebugInfo) const; + + std::string disassembleBinary(ID3DBlob* shaderBinary) const; private: DISALLOW_COPY_AND_ASSIGN(HLSLCompiler); HMODULE mD3DCompilerModule; - CompileFuncPtr mD3DCompileFunc; + pD3DCompile mD3DCompileFunc; + pD3DDisassemble mD3DDisassembleFunc; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp index 0854b968da..12b919ab5a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.cpp @@ -19,8 +19,8 @@ ImageD3D::ImageD3D() ImageD3D *ImageD3D::makeImageD3D(Image *img) { - ASSERT(HAS_DYNAMIC_TYPE(rx::ImageD3D*, img)); - return static_cast(img); + ASSERT(HAS_DYNAMIC_TYPE(ImageD3D*, img)); + return static_cast(img); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h index 60a6ffdf37..554ca0cee0 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ImageD3D.h @@ -17,6 +17,8 @@ namespace gl { class Framebuffer; +struct ImageIndex; +struct Box; } namespace rx @@ -33,14 +35,11 @@ class ImageD3D : public Image virtual bool isDirty() const = 0; - virtual void setManagedSurface2D(TextureStorage *storage, int level) {}; - virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level) {}; - virtual void setManagedSurface3D(TextureStorage *storage, int level) {}; - virtual void setManagedSurface2DArray(TextureStorage *storage, int layer, int level) {}; - virtual bool copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - virtual bool copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0; - virtual bool copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) = 0; - virtual bool copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) = 0; + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface3D(TextureStorage *storage, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error setManagedSurface2DArray(TextureStorage *storage, int layer, int level) { return gl::Error(GL_NO_ERROR); }; + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) = 0; private: DISALLOW_COPY_AND_ASSIGN(ImageD3D); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp index 1dce1270d8..aa614f6cc4 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.cpp @@ -8,7 +8,7 @@ // class with derivations, classes that perform graphics API agnostic index buffer operations. #include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" namespace rx { @@ -35,7 +35,7 @@ void IndexBuffer::updateSerial() } -IndexBufferInterface::IndexBufferInterface(Renderer *renderer, bool dynamic) : mRenderer(renderer) +IndexBufferInterface::IndexBufferInterface(RendererD3D *renderer, bool dynamic) : mRenderer(renderer) { mIndexBuffer = renderer->createIndexBuffer(); @@ -130,7 +130,7 @@ gl::Error IndexBufferInterface::setBufferSize(unsigned int bufferSize, GLenum in } } -StreamingIndexBufferInterface::StreamingIndexBufferInterface(Renderer *renderer) : IndexBufferInterface(renderer, true) +StreamingIndexBufferInterface::StreamingIndexBufferInterface(RendererD3D *renderer) : IndexBufferInterface(renderer, true) { } @@ -165,7 +165,7 @@ gl::Error StreamingIndexBufferInterface::reserveBufferSpace(unsigned int size, G } -StaticIndexBufferInterface::StaticIndexBufferInterface(Renderer *renderer) : IndexBufferInterface(renderer, false) +StaticIndexBufferInterface::StaticIndexBufferInterface(RendererD3D *renderer) : IndexBufferInterface(renderer, false) { } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h index 1bb5ae2c4a..a34d30bbf3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexBuffer.h @@ -16,7 +16,7 @@ namespace rx { -class Renderer; +class RendererD3D; class IndexBuffer { @@ -50,7 +50,7 @@ class IndexBuffer class IndexBufferInterface { public: - IndexBufferInterface(Renderer *renderer, bool dynamic); + IndexBufferInterface(RendererD3D *renderer, bool dynamic); virtual ~IndexBufferInterface(); virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType) = 0; @@ -76,7 +76,7 @@ class IndexBufferInterface private: DISALLOW_COPY_AND_ASSIGN(IndexBufferInterface); - rx::Renderer *const mRenderer; + RendererD3D *const mRenderer; IndexBuffer* mIndexBuffer; @@ -87,7 +87,7 @@ class IndexBufferInterface class StreamingIndexBufferInterface : public IndexBufferInterface { public: - StreamingIndexBufferInterface(Renderer *renderer); + StreamingIndexBufferInterface(RendererD3D *renderer); ~StreamingIndexBufferInterface(); virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType); @@ -96,7 +96,7 @@ class StreamingIndexBufferInterface : public IndexBufferInterface class StaticIndexBufferInterface : public IndexBufferInterface { public: - explicit StaticIndexBufferInterface(Renderer *renderer); + explicit StaticIndexBufferInterface(RendererD3D *renderer); ~StaticIndexBufferInterface(); virtual gl::Error reserveBufferSpace(unsigned int size, GLenum indexType); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp index 8d455b4bf3..eddd9de887 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.cpp @@ -10,7 +10,7 @@ #include "libGLESv2/renderer/d3d/IndexDataManager.h" #include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/renderer/d3d/IndexBuffer.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/main.h" #include "libGLESv2/formatutils.h" @@ -57,7 +57,7 @@ static void ConvertIndices(GLenum sourceType, GLenum destinationType, const void else UNREACHABLE(); } -IndexDataManager::IndexDataManager(Renderer *renderer) +IndexDataManager::IndexDataManager(RendererD3D *renderer) : mRenderer(renderer), mStreamingBufferShort(NULL), mStreamingBufferInt(NULL) @@ -97,7 +97,14 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf ASSERT(typeInfo.bytes * static_cast(count) + offset <= storage->getSize()); - indices = static_cast(storage->getData()) + offset; + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; } StaticIndexBufferInterface *staticBuffer = storage ? storage->getStaticIndexBuffer() : NULL; @@ -183,7 +190,16 @@ gl::Error IndexDataManager::prepareIndexData(GLenum type, GLsizei count, gl::Buf return error; } - ConvertIndices(type, destinationIndexType, staticBuffer ? storage->getData() : indices, convertCount, output); + const uint8_t *dataPointer = reinterpret_cast(indices); + if (staticBuffer) + { + error = storage->getData(&dataPointer); + if (error.isError()) + { + return error; + } + } + ConvertIndices(type, destinationIndexType, dataPointer, convertCount, output); error = indexBuffer->unmapBuffer(); if (error.isError()) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h index 6d0b89e6d4..a1aee1588b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/IndexDataManager.h @@ -33,7 +33,7 @@ class StaticIndexBufferInterface; class StreamingIndexBufferInterface; class IndexBuffer; class BufferD3D; -class Renderer; +class RendererD3D; struct TranslatedIndexData { @@ -50,7 +50,7 @@ struct TranslatedIndexData class IndexDataManager { public: - explicit IndexDataManager(Renderer *renderer); + explicit IndexDataManager(RendererD3D *renderer); virtual ~IndexDataManager(); gl::Error prepareIndexData(GLenum type, GLsizei count, gl::Buffer *arrayElementBuffer, const GLvoid *indices, TranslatedIndexData *translated); @@ -60,7 +60,7 @@ class IndexDataManager DISALLOW_COPY_AND_ASSIGN(IndexDataManager); - Renderer *const mRenderer; + RendererD3D *const mRenderer; StreamingIndexBufferInterface *mStreamingBufferShort; StreamingIndexBufferInterface *mStreamingBufferInt; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp index d7d97cc2bd..75da78110e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp @@ -8,27 +8,163 @@ #include "libGLESv2/renderer/d3d/ProgramD3D.h" +#include "common/features.h" #include "common/utilities.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/Program.h" #include "libGLESv2/ProgramBinary.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/main.h" #include "libGLESv2/renderer/ShaderExecutable.h" #include "libGLESv2/renderer/d3d/DynamicHLSL.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/main.h" namespace rx { -ProgramD3D::ProgramD3D(rx::Renderer *renderer) +namespace +{ + +GLenum GetTextureType(GLenum samplerType) +{ + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return GL_TEXTURE_2D; + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return GL_TEXTURE_3D; + case GL_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return GL_TEXTURE_CUBE_MAP; + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + return GL_TEXTURE_CUBE_MAP; + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return GL_TEXTURE_2D_ARRAY; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +void GetDefaultInputLayoutFromShader(const std::vector &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]) +{ + size_t layoutIndex = 0; + for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++) + { + ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS); + + const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex]; + + if (shaderAttr.type != GL_NONE) + { + GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type); + + for (size_t rowIndex = 0; static_cast(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++) + { + gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex]; + + defaultFormat->mType = gl::VariableComponentType(transposedType); + defaultFormat->mNormalized = false; + defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool + defaultFormat->mComponents = gl::VariableColumnCount(transposedType); + } + } + } +} + +std::vector GetDefaultOutputLayoutFromShader(const std::vector &shaderOutputVars) +{ + std::vector defaultPixelOutput(1); + + ASSERT(!shaderOutputVars.empty()); + defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex; + + return defaultPixelOutput; +} + +bool IsRowMajorLayout(const sh::InterfaceBlockField &var) +{ + return var.isRowMajorLayout; +} + +bool IsRowMajorLayout(const sh::ShaderVariable &var) +{ + return false; +} + +} + +ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[], + const GLenum signature[], + ShaderExecutable *shaderExecutable) + : mShaderExecutable(shaderExecutable) +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputs[attributeIndex] = inputLayout[attributeIndex]; + mSignature[attributeIndex] = signature[attributeIndex]; + } +} + +ProgramD3D::VertexExecutable::~VertexExecutable() +{ + SafeDelete(mShaderExecutable); +} + +bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const +{ + for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (mSignature[attributeIndex] != signature[attributeIndex]) + { + return false; + } + } + + return true; +} + +ProgramD3D::PixelExecutable::PixelExecutable(const std::vector &outputSignature, ShaderExecutable *shaderExecutable) + : mOutputSignature(outputSignature), + mShaderExecutable(shaderExecutable) +{ +} + +ProgramD3D::PixelExecutable::~PixelExecutable() +{ + SafeDelete(mShaderExecutable); +} + +ProgramD3D::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D) +{ +} + +ProgramD3D::ProgramD3D(RendererD3D *renderer) : ProgramImpl(), mRenderer(renderer), mDynamicHLSL(NULL), - mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), - mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE), + mGeometryExecutable(NULL), + mVertexWorkarounds(ANGLE_D3D_WORKAROUND_NONE), + mPixelWorkarounds(ANGLE_D3D_WORKAROUND_NONE), + mUsesPointSize(false), mVertexUniformStorage(NULL), - mFragmentUniformStorage(NULL) + mFragmentUniformStorage(NULL), + mUsedVertexSamplerRange(0), + mUsedPixelSamplerRange(0), + mDirtySamplerMapping(true), + mShaderVersion(100) { - mDynamicHLSL = new rx::DynamicHLSL(renderer); + mDynamicHLSL = new DynamicHLSL(renderer); } ProgramD3D::~ProgramD3D() @@ -49,13 +185,344 @@ const ProgramD3D *ProgramD3D::makeProgramD3D(const ProgramImpl *impl) return static_cast(impl); } -bool ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +bool ProgramD3D::usesPointSpriteEmulation() const { + return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4; +} + +bool ProgramD3D::usesGeometryShader() const +{ + return usesPointSpriteEmulation(); +} + +GLint ProgramD3D::getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const +{ + GLint logicalTextureUnit = -1; + + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < caps.maxTextureImageUnits); + if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active) + { + logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit; + } + break; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < caps.maxVertexTextureImageUnits); + if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active) + { + logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit; + } + break; + default: UNREACHABLE(); + } + + if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast(caps.maxCombinedTextureImageUnits)) + { + return logicalTextureUnit; + } + + return -1; +} + +// Returns the texture type for a given Direct3D 9 sampler type and +// index (0-15 for the pixel shader and 0-3 for the vertex shader). +GLenum ProgramD3D::getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + ASSERT(samplerIndex < mSamplersPS.size()); + ASSERT(mSamplersPS[samplerIndex].active); + return mSamplersPS[samplerIndex].textureType; + case gl::SAMPLER_VERTEX: + ASSERT(samplerIndex < mSamplersVS.size()); + ASSERT(mSamplersVS[samplerIndex].active); + return mSamplersVS[samplerIndex].textureType; + default: UNREACHABLE(); + } + + return GL_TEXTURE_2D; +} + +GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const +{ + switch (type) + { + case gl::SAMPLER_PIXEL: + return mUsedPixelSamplerRange; + case gl::SAMPLER_VERTEX: + return mUsedVertexSamplerRange; + default: + UNREACHABLE(); + return 0; + } +} + +void ProgramD3D::updateSamplerMapping() +{ + if (!mDirtySamplerMapping) + { + return; + } + + mDirtySamplerMapping = false; + + // Retrieve sampler uniform values + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + gl::LinkedUniform *targetUniform = mUniforms[uniformIndex]; + + if (targetUniform->dirty) + { + if (gl::IsSampler(targetUniform->type)) + { + int count = targetUniform->elementCount(); + GLint (*v)[4] = reinterpret_cast(targetUniform->data); + + if (targetUniform->isReferencedByFragmentShader()) + { + unsigned int firstIndex = targetUniform->psRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersPS.size()) + { + ASSERT(mSamplersPS[samplerIndex].active); + mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + + if (targetUniform->isReferencedByVertexShader()) + { + unsigned int firstIndex = targetUniform->vsRegisterIndex; + + for (int i = 0; i < count; i++) + { + unsigned int samplerIndex = firstIndex + i; + + if (samplerIndex < mSamplersVS.size()) + { + ASSERT(mSamplersVS[samplerIndex].active); + mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0]; + } + } + } + } + } + } +} + +bool ProgramD3D::validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) +{ + // if any two active samplers in a program are of different types, but refer to the same + // texture image unit, and this is the current program, then ValidateProgram will fail, and + // DrawArrays and DrawElements will issue the INVALID_OPERATION error. + updateSamplerMapping(); + + std::vector textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE); + + for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i) + { + if (mSamplersPS[i].active) + { + unsigned int unit = mSamplersPS[i].logicalTextureUnit; + + if (unit >= textureUnitTypes.size()) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); + } + + return false; + } + + if (textureUnitTypes[unit] != GL_NONE) + { + if (mSamplersPS[i].textureType != textureUnitTypes[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitTypes[unit] = mSamplersPS[i].textureType; + } + } + } + + for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i) + { + if (mSamplersVS[i].active) + { + unsigned int unit = mSamplersVS[i].logicalTextureUnit; + + if (unit >= textureUnitTypes.size()) + { + if (infoLog) + { + infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size()); + } + + return false; + } + + if (textureUnitTypes[unit] != GL_NONE) + { + if (mSamplersVS[i].textureType != textureUnitTypes[unit]) + { + if (infoLog) + { + infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit); + } + + return false; + } + } + else + { + textureUnitTypes[unit] = mSamplersVS[i].textureType; + } + } + } + + return true; +} + +gl::LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) +{ + stream->readInt(&mShaderVersion); + + const unsigned int psSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < psSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersPS.push_back(sampler); + } + const unsigned int vsSamplerCount = stream->readInt(); + for (unsigned int i = 0; i < vsSamplerCount; ++i) + { + Sampler sampler; + stream->readBool(&sampler.active); + stream->readInt(&sampler.logicalTextureUnit); + stream->readInt(&sampler.textureType); + mSamplersVS.push_back(sampler); + } + + stream->readInt(&mUsedVertexSamplerRange); + stream->readInt(&mUsedPixelSamplerRange); + + const unsigned int uniformCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniforms.resize(uniformCount); + for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) + { + GLenum type = stream->readInt(); + GLenum precision = stream->readInt(); + std::string name = stream->readString(); + unsigned int arraySize = stream->readInt(); + int blockIndex = stream->readInt(); + + int offset = stream->readInt(); + int arrayStride = stream->readInt(); + int matrixStride = stream->readInt(); + bool isRowMajorMatrix = stream->readBool(); + + const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix); + + gl::LinkedUniform *uniform = new gl::LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo); + + stream->readInt(&uniform->psRegisterIndex); + stream->readInt(&uniform->vsRegisterIndex); + stream->readInt(&uniform->registerCount); + stream->readInt(&uniform->registerElement); + + mUniforms[uniformIndex] = uniform; + } + + const unsigned int uniformIndexCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformIndex.resize(uniformIndexCount); + for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++) + { + stream->readString(&mUniformIndex[uniformIndexIndex].name); + stream->readInt(&mUniformIndex[uniformIndexIndex].element); + stream->readInt(&mUniformIndex[uniformIndexIndex].index); + } + + unsigned int uniformBlockCount = stream->readInt(); + if (stream->error()) + { + infoLog.append("Invalid program binary."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + mUniformBlocks.resize(uniformBlockCount); + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex) + { + std::string name = stream->readString(); + unsigned int elementIndex = stream->readInt(); + unsigned int dataSize = stream->readInt(); + + gl::UniformBlock *uniformBlock = new gl::UniformBlock(name, elementIndex, dataSize); + + stream->readInt(&uniformBlock->psRegisterIndex); + stream->readInt(&uniformBlock->vsRegisterIndex); + + unsigned int numMembers = stream->readInt(); + uniformBlock->memberUniformIndexes.resize(numMembers); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++) + { + stream->readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]); + } + + mUniformBlocks[uniformBlockIndex] = uniformBlock; + } + + stream->readInt(&mTransformFeedbackBufferMode); + const unsigned int transformFeedbackVaryingCount = stream->readInt(); + mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount); + for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++) + { + gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex]; + + stream->readString(&varying.name); + stream->readInt(&varying.type); + stream->readInt(&varying.size); + stream->readString(&varying.semanticName); + stream->readInt(&varying.semanticIndex); + stream->readInt(&varying.semanticIndexCount); + } + stream->readString(&mVertexHLSL); stream->readInt(&mVertexWorkarounds); stream->readString(&mPixelHLSL); stream->readInt(&mPixelWorkarounds); stream->readBool(&mUsesFragDepth); + stream->readBool(&mUsesPointSize); const size_t pixelShaderKeySize = stream->readInt(); mPixelShaderKey.resize(pixelShaderKeySize); @@ -67,109 +534,513 @@ bool ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex); } - return true; + const unsigned char* binary = reinterpret_cast(stream->data()); + + const unsigned int vertexShaderCount = stream->readInt(); + for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++) + { + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + gl::VertexFormat *vertexInput = &inputLayout[inputIndex]; + stream->readInt(&vertexInput->mType); + stream->readInt(&vertexInput->mNormalized); + stream->readInt(&vertexInput->mComponents); + stream->readBool(&vertexInput->mPureInteger); + } + + unsigned int vertexShaderSize = stream->readInt(); + const unsigned char *vertexShaderFunction = binary + stream->offset(); + + ShaderExecutable *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize, + SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create vertex shader."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // generated converted input layout + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + // add new binary + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable)); + + stream->skip(vertexShaderSize); + } + + const size_t pixelShaderCount = stream->readInt(); + for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++) + { + const size_t outputCount = stream->readInt(); + std::vector outputs(outputCount); + for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++) + { + stream->readInt(&outputs[outputIndex]); + } + + const size_t pixelShaderSize = stream->readInt(); + const unsigned char *pixelShaderFunction = binary + stream->offset(); + ShaderExecutable *shaderExecutable = NULL; + gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &shaderExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + + if (!shaderExecutable) + { + infoLog.append("Could not create pixel shader."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + // add new binary + mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable)); + + stream->skip(pixelShaderSize); + } + + unsigned int geometryShaderSize = stream->readInt(); + + if (geometryShaderSize > 0) + { + const unsigned char *geometryShaderFunction = binary + stream->offset(); + gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + &mGeometryExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + + if (!mGeometryExecutable) + { + infoLog.append("Could not create geometry shader."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + stream->skip(geometryShaderSize); + } + + GUID binaryIdentifier = {0}; + stream->readBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + GUID identifier = mRenderer->getAdapterIdentifier(); + if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0) + { + infoLog.append("Invalid program binary."); + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); + } + + initializeUniformStorage(); + + return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); } -bool ProgramD3D::save(gl::BinaryOutputStream *stream) +gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) { + stream->writeInt(mShaderVersion); + + stream->writeInt(mSamplersPS.size()); + for (unsigned int i = 0; i < mSamplersPS.size(); ++i) + { + stream->writeInt(mSamplersPS[i].active); + stream->writeInt(mSamplersPS[i].logicalTextureUnit); + stream->writeInt(mSamplersPS[i].textureType); + } + + stream->writeInt(mSamplersVS.size()); + for (unsigned int i = 0; i < mSamplersVS.size(); ++i) + { + stream->writeInt(mSamplersVS[i].active); + stream->writeInt(mSamplersVS[i].logicalTextureUnit); + stream->writeInt(mSamplersVS[i].textureType); + } + + stream->writeInt(mUsedVertexSamplerRange); + stream->writeInt(mUsedPixelSamplerRange); + + stream->writeInt(mUniforms.size()); + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + stream->writeInt(uniform.type); + stream->writeInt(uniform.precision); + stream->writeString(uniform.name); + stream->writeInt(uniform.arraySize); + stream->writeInt(uniform.blockIndex); + + stream->writeInt(uniform.blockInfo.offset); + stream->writeInt(uniform.blockInfo.arrayStride); + stream->writeInt(uniform.blockInfo.matrixStride); + stream->writeInt(uniform.blockInfo.isRowMajorMatrix); + + stream->writeInt(uniform.psRegisterIndex); + stream->writeInt(uniform.vsRegisterIndex); + stream->writeInt(uniform.registerCount); + stream->writeInt(uniform.registerElement); + } + + stream->writeInt(mUniformIndex.size()); + for (size_t i = 0; i < mUniformIndex.size(); ++i) + { + stream->writeString(mUniformIndex[i].name); + stream->writeInt(mUniformIndex[i].element); + stream->writeInt(mUniformIndex[i].index); + } + + stream->writeInt(mUniformBlocks.size()); + for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex) + { + const gl::UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex]; + + stream->writeString(uniformBlock.name); + stream->writeInt(uniformBlock.elementIndex); + stream->writeInt(uniformBlock.dataSize); + + stream->writeInt(uniformBlock.memberUniformIndexes.size()); + for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++) + { + stream->writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]); + } + + stream->writeInt(uniformBlock.psRegisterIndex); + stream->writeInt(uniformBlock.vsRegisterIndex); + } + + stream->writeInt(mTransformFeedbackBufferMode); + stream->writeInt(mTransformFeedbackLinkedVaryings.size()); + for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++) + { + const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i]; + + stream->writeString(varying.name); + stream->writeInt(varying.type); + stream->writeInt(varying.size); + stream->writeString(varying.semanticName); + stream->writeInt(varying.semanticIndex); + stream->writeInt(varying.semanticIndexCount); + } + stream->writeString(mVertexHLSL); stream->writeInt(mVertexWorkarounds); stream->writeString(mPixelHLSL); stream->writeInt(mPixelWorkarounds); stream->writeInt(mUsesFragDepth); + stream->writeInt(mUsesPointSize); - const std::vector &pixelShaderKey = mPixelShaderKey; + const std::vector &pixelShaderKey = mPixelShaderKey; stream->writeInt(pixelShaderKey.size()); for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++) { - const rx::PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; + const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex]; stream->writeInt(variable.type); stream->writeString(variable.name); stream->writeString(variable.source); stream->writeInt(variable.outputIndex); } - return true; + stream->writeInt(mVertexExecutables.size()); + for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++) + { + VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex]; + + for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++) + { + const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex]; + stream->writeInt(vertexInput.mType); + stream->writeInt(vertexInput.mNormalized); + stream->writeInt(vertexInput.mComponents); + stream->writeInt(vertexInput.mPureInteger); + } + + size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength(); + stream->writeInt(vertexShaderSize); + + const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(vertexBlob, vertexShaderSize); + } + + stream->writeInt(mPixelExecutables.size()); + for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++) + { + PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex]; + + const std::vector outputs = pixelExecutable->outputSignature(); + stream->writeInt(outputs.size()); + for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++) + { + stream->writeInt(outputs[outputIndex]); + } + + size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength(); + stream->writeInt(pixelShaderSize); + + const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction(); + stream->writeBytes(pixelBlob, pixelShaderSize); + } + + size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0; + stream->writeInt(geometryShaderSize); + + if (mGeometryExecutable != NULL && geometryShaderSize > 0) + { + const uint8_t *geometryBlob = mGeometryExecutable->getFunction(); + stream->writeBytes(geometryBlob, geometryShaderSize); + } + + GUID binaryIdentifier = mRenderer->getAdapterIdentifier(); + stream->writeBytes(reinterpret_cast(&binaryIdentifier), sizeof(GUID)); + + return gl::Error(GL_NO_ERROR); } -rx::ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector &outputSignature, - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers) +gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExecutable) { + std::vector outputs; + + const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender(mRenderer->getWorkarounds()); + + for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) + { + const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment]; + + if (colorbuffer) + { + outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding()); + } + else + { + outputs.push_back(GL_NONE); + } + } + + return getPixelExecutableForOutputLayout(outputs, outExecutable); +} + +gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector &outputSignature, ShaderExecutable **outExectuable) +{ + for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++) + { + if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) + { + *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth, outputSignature); // Generate new pixel executable - rx::ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(infoLog, finalPixelHLSL.c_str(), rx::SHADER_PIXEL, - transformFeedbackLinkedVaryings, separatedOutputBuffers, - mPixelWorkarounds); + gl::InfoLog tempInfoLog; + ShaderExecutable *pixelExecutable = NULL; + gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mPixelWorkarounds, &pixelExecutable); + if (error.isError()) + { + return error; + } - return pixelExecutable; + if (!pixelExecutable) + { + std::vector tempCharBuffer(tempInfoLog.getLength() + 3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable)); + } + + *outExectuable = pixelExecutable; + return gl::Error(GL_NO_ERROR); } -rx::ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(gl::InfoLog &infoLog, - const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], - const sh::Attribute shaderAttributes[], - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers) +gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable) { + GLenum signature[gl::MAX_VERTEX_ATTRIBS]; + getInputLayoutSignature(inputLayout, signature); + + for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++) + { + if (mVertexExecutables[executableIndex]->matchesSignature(signature)) + { + *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); + return gl::Error(GL_NO_ERROR); + } + } + // Generate new dynamic layout with attribute conversions - std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, shaderAttributes); + std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes); // Generate new vertex executable - rx::ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(infoLog, finalVertexHLSL.c_str(), - rx::SHADER_VERTEX, - transformFeedbackLinkedVaryings, separatedOutputBuffers, - mVertexWorkarounds); + gl::InfoLog tempInfoLog; + ShaderExecutable *vertexExecutable = NULL; + gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL, SHADER_VERTEX, + mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + mVertexWorkarounds, &vertexExecutable); + if (error.isError()) + { + return error; + } - return vertexExecutable; + if (!vertexExecutable) + { + std::vector tempCharBuffer(tempInfoLog.getLength()+3); + tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]); + ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]); + } + else + { + mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable)); + } + + *outExectuable = vertexExecutable; + return gl::Error(GL_NO_ERROR); } -bool ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, int *registers, - std::vector *linkedVaryings, std::map *outputVariables) +gl::LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers) { - rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); - rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS]; + GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout); + ShaderExecutable *defaultVertexExecutable = NULL; + gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + + std::vector defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey()); + ShaderExecutable *defaultPixelExecutable = NULL; + error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + + if (usesGeometryShader()) + { + std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D); + + + error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings, + (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS), + ANGLE_D3D_WORKAROUND_NONE, &mGeometryExecutable); + if (error.isError()) + { + return gl::LinkResult(false, error); + } + } + +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + if (usesGeometryShader() && mGeometryExecutable) + { + // Geometry shaders are currently only used internally, so there is no corresponding shader object at the interface level + // For now the geometry shader debug info is pre-pended to the vertex shader, this is a bit of a clutch + vertexShaderD3D->appendDebugInfo("// GEOMETRY SHADER BEGIN\n\n"); + vertexShaderD3D->appendDebugInfo(mGeometryExecutable->getDebugInfo()); + vertexShaderD3D->appendDebugInfo("\nGEOMETRY SHADER END\n\n\n"); + } + + if (defaultVertexExecutable) + { + vertexShaderD3D->appendDebugInfo(defaultVertexExecutable->getDebugInfo()); + } + + if (defaultPixelExecutable) + { + fragmentShaderD3D->appendDebugInfo(defaultPixelExecutable->getDebugInfo()); + } +#endif + + bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable)); + return gl::LinkResult(linkSuccess, gl::Error(GL_NO_ERROR)); +} + +gl::LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables) +{ + ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation()); + ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation()); + + mSamplersPS.resize(data.caps->maxTextureImageUnits); + mSamplersVS.resize(data.caps->maxVertexTextureImageUnits); + + mTransformFeedbackBufferMode = transformFeedbackBufferMode; mPixelHLSL = fragmentShaderD3D->getTranslatedSource(); mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds(); mVertexHLSL = vertexShaderD3D->getTranslatedSource(); mVertexWorkarounds = vertexShaderD3D->getD3DWorkarounds(); + mShaderVersion = vertexShaderD3D->getShaderVersion(); // Map the varyings to the register file - rx::VaryingPacking packing = { NULL }; + VaryingPacking packing = { NULL }; *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings); if (*registers < 0) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader)) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } - if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, + if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings, linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth)) { - return false; + return gl::LinkResult(false, gl::Error(GL_NO_ERROR)); } - return true; + mUsesPointSize = vertexShaderD3D->usesPointSize(); + + return gl::LinkResult(true, gl::Error(GL_NO_ERROR)); } -void ProgramD3D::initializeUniformStorage(const std::vector &uniforms) +void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const +{ + mDynamicHLSL->getInputLayoutSignature(inputLayout, signature); +} + +void ProgramD3D::initializeUniformStorage() { // Compute total default block size unsigned int vertexRegisters = 0; unsigned int fragmentRegisters = 0; - for (size_t uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++) + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) { - const gl::LinkedUniform &uniform = *uniforms[uniformIndex]; + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; if (!gl::IsSampler(uniform.type)) { @@ -188,18 +1059,867 @@ void ProgramD3D::initializeUniformStorage(const std::vector mFragmentUniformStorage = mRenderer->createUniformStorage(fragmentRegisters * 16u); } +gl::Error ProgramD3D::applyUniforms() +{ + updateSamplerMapping(); + + gl::Error error = mRenderer->applyUniforms(*this, mUniforms); + if (error.isError()) + { + return error; + } + + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + mUniforms[uniformIndex]->dirty = false; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error ProgramD3D::applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps) +{ + ASSERT(boundBuffers.size() == mUniformBlocks.size()); + + const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL}; + const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL}; + + const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers(); + const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers(); + + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[uniformBlockIndex]; + gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex]; + + ASSERT(uniformBlock && uniformBuffer); + + if (uniformBuffer->getSize() < uniformBlock->dataSize) + { + // undefined behaviour + return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small."); + } + + // Unnecessary to apply an unreferenced standard or shared UBO + if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader()) + { + continue; + } + + if (uniformBlock->isReferencedByVertexShader()) + { + unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS; + ASSERT(vertexUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < caps.maxVertexUniformBlocks); + vertexUniformBuffers[registerIndex] = uniformBuffer; + } + + if (uniformBlock->isReferencedByFragmentShader()) + { + unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS; + ASSERT(fragmentUniformBuffers[registerIndex] == NULL); + ASSERT(registerIndex < caps.maxFragmentUniformBlocks); + fragmentUniformBuffers[registerIndex] = uniformBuffer; + } + } + + return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers); +} + +bool ProgramD3D::assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps) +{ + if (shader == GL_VERTEX_SHADER) + { + uniformBlock->vsRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks) + { + infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks); + return false; + } + } + else if (shader == GL_FRAGMENT_SHADER) + { + uniformBlock->psRegisterIndex = registerIndex; + if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks) + { + infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks); + return false; + } + } + else UNREACHABLE(); + + return true; +} + +void ProgramD3D::dirtyAllUniforms() +{ + unsigned int numUniforms = mUniforms.size(); + for (unsigned int index = 0; index < numUniforms; index++) + { + mUniforms[index]->dirty = true; + } +} + +void ProgramD3D::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + setUniform(location, count, v, GL_FLOAT); +} + +void ProgramD3D::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC2); +} + +void ProgramD3D::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC3); +} + +void ProgramD3D::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + setUniform(location, count, v, GL_FLOAT_VEC4); +} + +void ProgramD3D::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2); +} + +void ProgramD3D::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3); +} + +void ProgramD3D::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4); +} + +void ProgramD3D::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3); +} + +void ProgramD3D::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2); +} + +void ProgramD3D::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4); +} + +void ProgramD3D::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2); +} + +void ProgramD3D::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4); +} + +void ProgramD3D::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) +{ + setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3); +} + +void ProgramD3D::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT); +} + +void ProgramD3D::setUniform2iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC2); +} + +void ProgramD3D::setUniform3iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC3); +} + +void ProgramD3D::setUniform4iv(GLint location, GLsizei count, const GLint *v) +{ + setUniform(location, count, v, GL_INT_VEC4); +} + +void ProgramD3D::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT); +} + +void ProgramD3D::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC2); +} + +void ProgramD3D::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC3); +} + +void ProgramD3D::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) +{ + setUniform(location, count, v, GL_UNSIGNED_INT_VEC4); +} + +void ProgramD3D::getUniformfv(GLint location, GLfloat *params) +{ + getUniformv(location, params, GL_FLOAT); +} + +void ProgramD3D::getUniformiv(GLint location, GLint *params) +{ + getUniformv(location, params, GL_INT); +} + +void ProgramD3D::getUniformuiv(GLint location, GLuint *params) +{ + getUniformv(location, params, GL_UNSIGNED_INT); +} + +bool ProgramD3D::linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps) +{ + const ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader.getImplementation()); + const ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader.getImplementation()); + + const std::vector &vertexUniforms = vertexShader.getUniforms(); + const std::vector &fragmentUniforms = fragmentShader.getUniforms(); + + // Check that uniforms defined in the vertex and fragment shaders are identical + typedef std::map UniformMap; + UniformMap linkedUniforms; + + for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++) + { + const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex]; + linkedUniforms[vertexUniform.name] = &vertexUniform; + } + + for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++) + { + const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex]; + UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name); + if (entry != linkedUniforms.end()) + { + const sh::Uniform &vertexUniform = *entry->second; + const std::string &uniformName = "uniform '" + vertexUniform.name + "'"; + if (!gl::ProgramBinary::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform)) + { + return false; + } + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = vertexUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name)); + } + } + + for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++) + { + const sh::Uniform &uniform = fragmentUniforms[uniformIndex]; + + if (uniform.staticUse) + { + defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name)); + } + } + + if (!indexUniforms(infoLog, caps)) + { + return false; + } + + initializeUniformStorage(); + + // special case for gl_DepthRange, the only built-in uniform (also a struct) + if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange()) + { + const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo(); + + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo)); + mUniforms.push_back(new gl::LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo)); + } + + return true; +} + +void ProgramD3D::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister) +{ + ShShaderOutput outputType = ShaderD3D::getCompilerOutputType(shader); + sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType)); + encoder.skipRegisters(uniformRegister); + + defineUniform(shader, uniform, uniform.name, &encoder); +} + +void ProgramD3D::defineUniform(GLenum shader, const sh::ShaderVariable &uniform, + const std::string &fullName, sh::HLSLBlockEncoder *encoder) +{ + if (uniform.isStruct()) + { + for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++) + { + const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : ""); + + encoder->enterAggregateType(); + + for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++) + { + const sh::ShaderVariable &field = uniform.fields[fieldIndex]; + const std::string &fieldFullName = (fullName + elementString + "." + field.name); + + defineUniform(shader, field, fieldFullName, encoder); + } + + encoder->exitAggregateType(); + } + } + else // Not a struct + { + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->enterAggregateType(); + } + + gl::LinkedUniform *linkedUniform = getUniformByName(fullName); + + if (!linkedUniform) + { + linkedUniform = new gl::LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize, + -1, sh::BlockMemberInfo::getDefaultBlockInfo()); + ASSERT(linkedUniform); + linkedUniform->registerElement = encoder->getCurrentElement(); + mUniforms.push_back(linkedUniform); + } + + ASSERT(linkedUniform->registerElement == encoder->getCurrentElement()); + + if (shader == GL_FRAGMENT_SHADER) + { + linkedUniform->psRegisterIndex = encoder->getCurrentRegister(); + } + else if (shader == GL_VERTEX_SHADER) + { + linkedUniform->vsRegisterIndex = encoder->getCurrentRegister(); + } + else UNREACHABLE(); + + // Advance the uniform offset, to track registers allocation for structs + encoder->encodeType(uniform.type, uniform.arraySize, false); + + // Arrays are treated as aggregate types + if (uniform.isArray()) + { + encoder->exitAggregateType(); + } + } +} + +template +static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag) +{ + ASSERT(dest != NULL); + ASSERT(dirtyFlag != NULL); + + *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0); + *dest = source; +} + +template +void ProgramD3D::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType) +{ + const int components = gl::VariableComponentCount(targetUniformType); + const GLenum targetBoolType = gl::VariableBoolVectorType(targetUniformType); + + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + + if (targetUniform->type == targetUniformType) + { + T *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + T *dest = target + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, source[c], &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, T(0), &targetUniform->dirty); + } + } + } + else if (targetUniform->type == targetBoolType) + { + GLint *boolParams = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + for (int i = 0; i < count; i++) + { + GLint *dest = boolParams + (i * 4); + const T *source = v + (i * components); + + for (int c = 0; c < components; c++) + { + SetIfDirty(dest + c, (source[c] == static_cast(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty); + } + for (int c = components; c < 4; c++) + { + SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty); + } + } + } + else if (gl::IsSampler(targetUniform->type)) + { + ASSERT(targetUniformType == GL_INT); + + GLint *target = reinterpret_cast(targetUniform->data) + mUniformIndex[location].element * 4; + + bool wasDirty = targetUniform->dirty; + + for (int i = 0; i < count; i++) + { + GLint *dest = target + (i * 4); + const GLint *source = reinterpret_cast(v) + (i * components); + + SetIfDirty(dest + 0, source[0], &targetUniform->dirty); + SetIfDirty(dest + 1, 0, &targetUniform->dirty); + SetIfDirty(dest + 2, 0, &targetUniform->dirty); + SetIfDirty(dest + 3, 0, &targetUniform->dirty); + } + + if (!wasDirty && targetUniform->dirty) + { + mDirtySamplerMapping = true; + } + } + else UNREACHABLE(); +} + +template +bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetHeight, srcWidth); + int copyHeight = std::min(targetWidth, srcHeight); + + for (int x = 0; x < copyWidth; x++) + { + for (int y = 0; y < copyHeight; y++) + { + SetIfDirty(target + (x * targetWidth + y), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyWidth; y++) + { + for (int x = copyHeight; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyWidth; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight) +{ + bool dirty = false; + int copyWidth = std::min(targetWidth, srcWidth); + int copyHeight = std::min(targetHeight, srcHeight); + + for (int y = 0; y < copyHeight; y++) + { + for (int x = 0; x < copyWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(value[y * srcWidth + x]), &dirty); + } + } + // clear unfilled right side + for (int y = 0; y < copyHeight; y++) + { + for (int x = copyWidth; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + // clear unfilled bottom. + for (int y = copyHeight; y < targetHeight; y++) + { + for (int x = 0; x < targetWidth; x++) + { + SetIfDirty(target + (y * targetWidth + x), static_cast(0), &dirty); + } + } + + return dirty; +} + +template +void ProgramD3D::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType) +{ + gl::LinkedUniform *targetUniform = getUniformByLocation(location); + + int elementCount = targetUniform->elementCount(); + + count = std::min(elementCount - (int)mUniformIndex[location].element, count); + const unsigned int targetMatrixStride = (4 * rows); + GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride); + + for (int i = 0; i < count; i++) + { + // Internally store matrices as transposed versions to accomodate HLSL matrix indexing + if (transpose == GL_FALSE) + { + targetUniform->dirty = transposeMatrix(target, value, 4, rows, rows, cols) || targetUniform->dirty; + } + else + { + targetUniform->dirty = expandMatrix(target, value, 4, rows, cols, rows) || targetUniform->dirty; + } + target += targetMatrixStride; + value += cols * rows; + } +} + +template +void ProgramD3D::getUniformv(GLint location, T *params, GLenum uniformType) +{ + gl::LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index]; + + if (gl::IsMatrixType(targetUniform->type)) + { + const int rows = gl::VariableRowCount(targetUniform->type); + const int cols = gl::VariableColumnCount(targetUniform->type); + transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows); + } + else if (uniformType == gl::VariableComponentType(targetUniform->type)) + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T), + size * sizeof(T)); + } + else + { + unsigned int size = gl::VariableComponentCount(targetUniform->type); + switch (gl::VariableComponentType(targetUniform->type)) + { + case GL_BOOL: + { + GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = (boolParams[i] == GL_FALSE) ? static_cast(0) : static_cast(1); + } + } + break; + + case GL_FLOAT: + { + GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(floatParams[i]); + } + } + break; + + case GL_INT: + { + GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(intParams[i]); + } + } + break; + + case GL_UNSIGNED_INT: + { + GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4; + + for (unsigned int i = 0; i < size; i++) + { + params[i] = static_cast(uintParams[i]); + } + } + break; + + default: UNREACHABLE(); + } + } +} + +template +void ProgramD3D::defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout) +{ + for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++) + { + const VarT &field = fields[uniformIndex]; + const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name); + + if (field.isStruct()) + { + bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field)); + + for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++) + { + encoder->enterAggregateType(); + + const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : ""); + defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout); + + encoder->exitAggregateType(); + } + } + else + { + bool isRowMajorMatrix = (gl::IsMatrixType(field.type) && inRowMajorLayout); + + sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix); + + gl::LinkedUniform *newUniform = new gl::LinkedUniform(field.type, field.precision, fieldName, field.arraySize, + blockIndex, memberInfo); + + // add to uniform list, but not index, since uniform block uniforms have no location + blockUniformIndexes->push_back(mUniforms.size()); + mUniforms.push_back(newUniform); + } + } +} + +bool ProgramD3D::defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, + const gl::Caps &caps) +{ + const ShaderD3D* shaderD3D = ShaderD3D::makeShaderD3D(shader.getImplementation()); + + // create uniform block entries if they do not exist + if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX) + { + std::vector blockUniformIndexes; + const unsigned int blockIndex = mUniformBlocks.size(); + + // define member uniforms + sh::BlockLayoutEncoder *encoder = NULL; + + if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD) + { + encoder = new sh::Std140BlockEncoder; + } + else + { + encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED); + } + ASSERT(encoder); + + defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout); + + size_t dataSize = encoder->getBlockSize(); + + // create all the uniform blocks + if (interfaceBlock.arraySize > 0) + { + for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++) + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + else + { + gl::UniformBlock *newUniformBlock = new gl::UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize); + newUniformBlock->memberUniformIndexes = blockUniformIndexes; + mUniformBlocks.push_back(newUniformBlock); + } + } + + if (interfaceBlock.staticUse) + { + // Assign registers to the uniform blocks + const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name); + const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize); + ASSERT(blockIndex != GL_INVALID_INDEX); + ASSERT(blockIndex + elementCount <= mUniformBlocks.size()); + + unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name); + + for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++) + { + gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement]; + ASSERT(uniformBlock->name == interfaceBlock.name); + + if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(), + interfaceBlockRegister + uniformBlockElement, caps)) + { + return false; + } + } + } + + return true; +} + +bool ProgramD3D::assignSamplers(unsigned int startSamplerIndex, + GLenum samplerType, + unsigned int samplerCount, + std::vector &outSamplers, + GLuint *outUsedRange) +{ + unsigned int samplerIndex = startSamplerIndex; + + do + { + if (samplerIndex < outSamplers.size()) + { + Sampler& sampler = outSamplers[samplerIndex]; + sampler.active = true; + sampler.textureType = GetTextureType(samplerType); + sampler.logicalTextureUnit = 0; + *outUsedRange = std::max(samplerIndex + 1, *outUsedRange); + } + else + { + return false; + } + + samplerIndex++; + } while (samplerIndex < startSamplerIndex + samplerCount); + + return true; +} + +bool ProgramD3D::indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps) +{ + ASSERT(gl::IsSampler(uniform.type)); + ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX); + + if (uniform.vsRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS, + &mUsedVertexSamplerRange)) + { + infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", + mSamplersVS.size()); + return false; + } + + unsigned int maxVertexVectors = mRenderer->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors; + if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors) + { + infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", + caps.maxVertexUniformVectors); + return false; + } + } + + if (uniform.psRegisterIndex != GL_INVALID_INDEX) + { + if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS, + &mUsedPixelSamplerRange)) + { + infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", + mSamplersPS.size()); + return false; + } + + unsigned int maxFragmentVectors = mRenderer->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors; + if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors) + { + infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", + caps.maxFragmentUniformVectors); + return false; + } + } + + return true; +} + +bool ProgramD3D::indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps) +{ + for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) + { + const gl::LinkedUniform &uniform = *mUniforms[uniformIndex]; + + if (gl::IsSampler(uniform.type)) + { + if (!indexSamplerUniform(uniform, infoLog, caps)) + { + return false; + } + } + + for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++) + { + mUniformIndex.push_back(gl::VariableLocation(uniform.name, arrayElementIndex, uniformIndex)); + } + } + + return true; +} + void ProgramD3D::reset() { + ProgramImpl::reset(); + + SafeDeleteContainer(mVertexExecutables); + SafeDeleteContainer(mPixelExecutables); + SafeDelete(mGeometryExecutable); + + mTransformFeedbackBufferMode = GL_NONE; + mVertexHLSL.clear(); - mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + mVertexWorkarounds = ANGLE_D3D_WORKAROUND_NONE; + mShaderVersion = 100; mPixelHLSL.clear(); - mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE; + mPixelWorkarounds = ANGLE_D3D_WORKAROUND_NONE; mUsesFragDepth = false; mPixelShaderKey.clear(); + mUsesPointSize = false; SafeDelete(mVertexUniformStorage); SafeDelete(mFragmentUniformStorage); + + mSamplersPS.clear(); + mSamplersVS.clear(); + + mUsedVertexSamplerRange = 0; + mUsedPixelSamplerRange = 0; + mDirtySamplerMapping = true; } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h index d645c57daa..4baab9aa19 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h @@ -10,6 +10,7 @@ #define LIBGLESV2_RENDERER_PROGRAMD3D_H_ #include "libGLESv2/renderer/ProgramImpl.h" +#include "libGLESv2/renderer/Workarounds.h" #include #include @@ -23,63 +24,194 @@ struct VertexFormat; namespace rx { - +class RendererD3D; class UniformStorage; class ProgramD3D : public ProgramImpl { public: - ProgramD3D(rx::Renderer *renderer); + ProgramD3D(RendererD3D *renderer); virtual ~ProgramD3D(); static ProgramD3D *makeProgramD3D(ProgramImpl *impl); static const ProgramD3D *makeProgramD3D(const ProgramImpl *impl); - Renderer *getRenderer() { return mRenderer; } - DynamicHLSL *getDynamicHLSL() { return mDynamicHLSL; } - const std::vector &getPixelShaderKey() { return mPixelShaderKey; } + const std::vector &getPixelShaderKey() { return mPixelShaderKey; } + int getShaderVersion() const { return mShaderVersion; } + GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } + + GLint getSamplerMapping(gl::SamplerType type, unsigned int samplerIndex, const gl::Caps &caps) const; + GLenum getSamplerTextureType(gl::SamplerType type, unsigned int samplerIndex) const; + GLint getUsedSamplerRange(gl::SamplerType type) const; + void updateSamplerMapping(); + bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps); + + bool usesPointSize() const { return mUsesPointSize; } + bool usesPointSpriteEmulation() const; + bool usesGeometryShader() const; GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; } - bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); - bool save(gl::BinaryOutputStream *stream); + gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream); + gl::Error save(gl::BinaryOutputStream *stream); - ShaderExecutable *getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector &outputSignature, - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers); - ShaderExecutable *getVertexExecutableForInputLayout(gl::InfoLog &infoLog, - const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], - const sh::Attribute shaderAttributes[], - const std::vector &transformFeedbackLinkedVaryings, - bool separatedOutputBuffers); + gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExectuable); + gl::Error getPixelExecutableForOutputLayout(const std::vector &outputLayout, ShaderExecutable **outExectuable); + gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable); + ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; } - bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, - const std::vector &transformFeedbackVaryings, int *registers, - std::vector *linkedVaryings, std::map *outputVariables); + gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader, + int registers); - // D3D only - void initializeUniformStorage(const std::vector &uniforms); + gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog, + gl::Shader *fragmentShader, gl::Shader *vertexShader, + const std::vector &transformFeedbackVaryings, + GLenum transformFeedbackBufferMode, + int *registers, std::vector *linkedVaryings, + std::map *outputVariables); + + void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const; + + void initializeUniformStorage(); + gl::Error applyUniforms(); + gl::Error applyUniformBuffers(const std::vector boundBuffers, const gl::Caps &caps); + bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader, + unsigned int registerIndex, const gl::Caps &caps); + void dirtyAllUniforms(); + + void setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + void setUniform1iv(GLint location, GLsizei count, const GLint *v); + void setUniform2iv(GLint location, GLsizei count, const GLint *v); + void setUniform3iv(GLint location, GLsizei count, const GLint *v); + void setUniform4iv(GLint location, GLsizei count, const GLint *v); + void setUniform1uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform2uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform3uiv(GLint location, GLsizei count, const GLuint *v); + void setUniform4uiv(GLint location, GLsizei count, const GLuint *v); + void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); + + void getUniformfv(GLint location, GLfloat *params); + void getUniformiv(GLint location, GLint *params); + void getUniformuiv(GLint location, GLuint *params); const UniformStorage &getVertexUniformStorage() const { return *mVertexUniformStorage; } const UniformStorage &getFragmentUniformStorage() const { return *mFragmentUniformStorage; } + bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader, + const gl::Caps &caps); + bool defineUniformBlock(gl::InfoLog &infoLog, const gl::Shader &shader, const sh::InterfaceBlock &interfaceBlock, const gl::Caps &caps); + void reset(); private: DISALLOW_COPY_AND_ASSIGN(ProgramD3D); - Renderer *mRenderer; + class VertexExecutable + { + public: + VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], + const GLenum signature[gl::MAX_VERTEX_ATTRIBS], + ShaderExecutable *shaderExecutable); + ~VertexExecutable(); + + bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const; + + const gl::VertexFormat *inputs() const { return mInputs; } + const GLenum *signature() const { return mSignature; } + ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } + + private: + gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS]; + GLenum mSignature[gl::MAX_VERTEX_ATTRIBS]; + ShaderExecutable *mShaderExecutable; + }; + + class PixelExecutable + { + public: + PixelExecutable(const std::vector &outputSignature, ShaderExecutable *shaderExecutable); + ~PixelExecutable(); + + bool matchesSignature(const std::vector &signature) const { return mOutputSignature == signature; } + + const std::vector &outputSignature() const { return mOutputSignature; } + ShaderExecutable *shaderExecutable() const { return mShaderExecutable; } + + private: + std::vector mOutputSignature; + ShaderExecutable *mShaderExecutable; + }; + + struct Sampler + { + Sampler(); + + bool active; + GLint logicalTextureUnit; + GLenum textureType; + }; + + void defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister); + void defineUniform(GLenum shader, const sh::ShaderVariable &uniform, const std::string &fullName, + sh::HLSLBlockEncoder *encoder); + bool indexSamplerUniform(const gl::LinkedUniform &uniform, gl::InfoLog &infoLog, const gl::Caps &caps); + bool indexUniforms(gl::InfoLog &infoLog, const gl::Caps &caps); + static bool assignSamplers(unsigned int startSamplerIndex, GLenum samplerType, unsigned int samplerCount, + std::vector &outSamplers, GLuint *outUsedRange); + + template + void setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType); + + template + void setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType); + + template + void getUniformv(GLint location, T *params, GLenum uniformType); + + template + void defineUniformBlockMembers(const std::vector &fields, const std::string &prefix, int blockIndex, + sh::BlockLayoutEncoder *encoder, std::vector *blockUniformIndexes, + bool inRowMajorLayout); + + RendererD3D *mRenderer; DynamicHLSL *mDynamicHLSL; + std::vector mVertexExecutables; + std::vector mPixelExecutables; + ShaderExecutable *mGeometryExecutable; + std::string mVertexHLSL; - rx::D3DWorkaroundType mVertexWorkarounds; + D3DWorkaroundType mVertexWorkarounds; std::string mPixelHLSL; - rx::D3DWorkaroundType mPixelWorkarounds; + D3DWorkaroundType mPixelWorkarounds; bool mUsesFragDepth; - std::vector mPixelShaderKey; + std::vector mPixelShaderKey; + + bool mUsesPointSize; UniformStorage *mVertexUniformStorage; UniformStorage *mFragmentUniformStorage; + + GLenum mTransformFeedbackBufferMode; + + std::vector mSamplersPS; + std::vector mSamplersVS; + GLuint mUsedVertexSamplerRange; + GLuint mUsedPixelSamplerRange; + bool mDirtySamplerMapping; + + int mShaderVersion; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp new file mode 100644 index 0000000000..cb4af367a2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp @@ -0,0 +1,108 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferD3d.cpp: Implements the RenderbufferD3D class, a specialization of RenderbufferImpl + + +#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" + +#include "libGLESv2/renderer/d3d/RendererD3D.h" +#include "libGLESv2/renderer/RenderTarget.h" + +namespace rx +{ +RenderbufferD3D::RenderbufferD3D(RendererD3D *renderer) : mRenderer(renderer) +{ + mRenderTarget = NULL; +} + +RenderbufferD3D::~RenderbufferD3D() +{ + SafeDelete(mRenderTarget); +} + +RenderbufferD3D *RenderbufferD3D::makeRenderbufferD3D(RenderbufferImpl *renderbuffer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RenderbufferD3D*, renderbuffer)); + return static_cast(renderbuffer); +} + +gl::Error RenderbufferD3D::setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) +{ + // If the renderbuffer parameters are queried, the calling function + // will expect one of the valid renderbuffer formats for use in + // glRenderbufferStorage, but we should create depth and stencil buffers + // as DEPTH24_STENCIL8 + GLenum creationFormat = internalformat; + if (internalformat == GL_DEPTH_COMPONENT16 || internalformat == GL_STENCIL_INDEX8) + { + creationFormat = GL_DEPTH24_STENCIL8_OES; + } + + RenderTarget *newRT = NULL; + gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT); + if (error.isError()) + { + return error; + } + + SafeDelete(mRenderTarget); + mRenderTarget = newRT; + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RenderbufferD3D::setStorage(SwapChain *swapChain, bool depth) +{ + RenderTarget *newRT = NULL; + gl::Error error = mRenderer->createRenderTarget(swapChain, depth, &newRT); + if (error.isError()) + { + return error; + } + + SafeDelete(mRenderTarget); + mRenderTarget = newRT; + + return gl::Error(GL_NO_ERROR); +} + +GLsizei RenderbufferD3D::getWidth() const +{ + return (mRenderTarget ? mRenderTarget->getWidth() : 0); +} + +GLsizei RenderbufferD3D::getHeight() const +{ + return (mRenderTarget ? mRenderTarget->getHeight() : 0); +} + +GLenum RenderbufferD3D::getInternalFormat() const +{ + return (mRenderTarget ? mRenderTarget->getInternalFormat() : GL_RGBA4); +} + +GLenum RenderbufferD3D::getActualFormat() const +{ + return (mRenderTarget ? mRenderTarget->getActualFormat() : GL_RGBA4); +} + +GLsizei RenderbufferD3D::getSamples() const +{ + return (mRenderTarget ? mRenderTarget->getSamples() : 0); +} + +RenderTarget *RenderbufferD3D::getRenderTarget() +{ + return mRenderTarget; +} + +unsigned int RenderbufferD3D::getRenderTargetSerial() const +{ + return (mRenderTarget ? mRenderTarget->getSerial() : 0); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h new file mode 100644 index 0000000000..9440a449f2 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RenderbufferD3D.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RenderbufferD3d.h: Defines the RenderbufferD3D class which implements RenderbufferImpl. + +#ifndef LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ +#define LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ + +#include "angle_gl.h" + +#include "common/angleutils.h" +#include "libGLESv2/renderer/RenderbufferImpl.h" + +namespace rx +{ +class RendererD3D; +class RenderTarget; +class SwapChain; + +class RenderbufferD3D : public RenderbufferImpl +{ + public: + RenderbufferD3D(RendererD3D *renderer); + virtual ~RenderbufferD3D(); + + static RenderbufferD3D *makeRenderbufferD3D(RenderbufferImpl *renderbuffer); + + virtual gl::Error setStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples) override; + gl::Error setStorage(SwapChain *swapChain, bool depth); + + virtual GLsizei getWidth() const; + virtual GLsizei getHeight() const; + virtual GLenum getInternalFormat() const; + virtual GLenum getActualFormat() const; + virtual GLsizei getSamples() const; + + RenderTarget *getRenderTarget(); + unsigned int getRenderTargetSerial() const; + + private: + DISALLOW_COPY_AND_ASSIGN(RenderbufferD3D); + + RendererD3D *mRenderer; + RenderTarget *mRenderTarget; +}; +} + +#endif // LIBGLESV2_RENDERER_RENDERBUFFERD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp new file mode 100644 index 0000000000..97da6da7fd --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp @@ -0,0 +1,796 @@ +// +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RendererD3D.cpp: Implementation of the base D3D Renderer. + +#include "libGLESv2/renderer/d3d/RendererD3D.h" + +#include "libGLESv2/renderer/d3d/IndexDataManager.h" +#include "libGLESv2/Framebuffer.h" +#include "libGLESv2/FramebufferAttachment.h" +#include "libGLESv2/ResourceManager.h" +#include "libGLESv2/State.h" +#include "libGLESv2/VertexArray.h" +#include "libGLESv2/formatutils.h" +#include "common/utilities.h" + +namespace rx +{ + +RendererD3D::RendererD3D(egl::Display *display) + : mDisplay(display) +{ +} + +RendererD3D::~RendererD3D() +{ + for (gl::TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); ++i) + { + i->second.set(NULL); + } + mIncompleteTextures.clear(); +} + +// static +RendererD3D *RendererD3D::makeRendererD3D(Renderer *renderer) +{ + ASSERT(HAS_DYNAMIC_TYPE(RendererD3D*, renderer)); + return static_cast(renderer); +} + +gl::Error RendererD3D::drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) +{ + ASSERT(data.state->getCurrentProgramId() != 0); + + gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count)) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + gl::VertexArray *vao = data.state->getVertexArray(); + TranslatedIndexData indexInfo; + indexInfo.indexRange = indexRange; + error = applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo); + if (error.isError()) + { + return error; + } + + GLsizei vertexCount = indexInfo.indexRange.length() + 1; + error = applyVertexBuffer(*data.state, indexInfo.indexRange.start, vertexCount, instances); + if (error.isError()) + { + return error; + } + + bool transformFeedbackActive = applyTransformFeedbackBuffers(data); + // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation + // layer. + ASSERT(!transformFeedbackActive); + + error = applyShaders(data, transformFeedbackActive); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawElements(mode, count, type, indices, vao->getElementArrayBuffer(), indexInfo, instances); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) +{ + ASSERT(data.state->getCurrentProgramId() != 0); + + gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); + programBinary->updateSamplerMapping(); + + gl::Error error = generateSwizzles(data); + if (error.isError()) + { + return error; + } + + if (!applyPrimitiveType(mode, count)) + { + return gl::Error(GL_NO_ERROR); + } + + error = applyRenderTarget(data, mode, false); + if (error.isError()) + { + return error; + } + + error = applyState(data, mode); + if (error.isError()) + { + return error; + } + + error = applyVertexBuffer(*data.state, first, count, instances); + if (error.isError()) + { + return error; + } + + bool transformFeedbackActive = applyTransformFeedbackBuffers(data); + + error = applyShaders(data, transformFeedbackActive); + if (error.isError()) + { + return error; + } + + error = applyTextures(data); + if (error.isError()) + { + return error; + } + + error = applyUniformBuffers(data); + if (error.isError()) + { + return error; + } + + if (!skipDraw(data, mode)) + { + error = drawArrays(mode, count, instances, transformFeedbackActive); + if (error.isError()) + { + return error; + } + + if (transformFeedbackActive) + { + markTransformFeedbackUsage(data); + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type) +{ + gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); + + size_t samplerRange = programBinary->getUsedSamplerRange(type); + + for (size_t i = 0; i < samplerRange; i++) + { + GLenum textureType = programBinary->getSamplerTextureType(type, i); + GLint textureUnit = programBinary->getSamplerMapping(type, i, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + if (texture->getSamplerState().swizzleRequired()) + { + gl::Error error = generateSwizzle(texture); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::generateSwizzles(const gl::Data &data) +{ + gl::Error error = generateSwizzles(data, gl::SAMPLER_VERTEX); + if (error.isError()) + { + return error; + } + + error = generateSwizzles(data, gl::SAMPLER_PIXEL); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the renderer +gl::Error RendererD3D::applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + ASSERT(framebufferObject && framebufferObject->completeness(data) == GL_FRAMEBUFFER_COMPLETE); + + gl::Error error = applyRenderTarget(framebufferObject); + if (error.isError()) + { + return error; + } + + float nearZ, farZ; + data.state->getDepthRange(&nearZ, &farZ); + setViewport(data.state->getViewport(), nearZ, farZ, drawMode, + data.state->getRasterizerState().frontFace, ignoreViewport); + + setScissorRectangle(data.state->getScissor(), data.state->isScissorTestEnabled()); + + return gl::Error(GL_NO_ERROR); +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D device +gl::Error RendererD3D::applyState(const gl::Data &data, GLenum drawMode) +{ + const gl::Framebuffer *framebufferObject = data.state->getDrawFramebuffer(); + int samples = framebufferObject->getSamples(data); + + gl::RasterizerState rasterizer = data.state->getRasterizerState(); + rasterizer.pointDrawMode = (drawMode == GL_POINTS); + rasterizer.multiSample = (samples != 0); + + gl::Error error = setRasterizerState(rasterizer); + if (error.isError()) + { + return error; + } + + unsigned int mask = 0; + if (data.state->isSampleCoverageEnabled()) + { + GLclampf coverageValue; + bool coverageInvert = false; + data.state->getSampleCoverageParams(&coverageValue, &coverageInvert); + if (coverageValue != 0) + { + float threshold = 0.5f; + + for (int i = 0; i < samples; ++i) + { + mask <<= 1; + + if ((i + 1) * coverageValue >= threshold) + { + threshold += 1.0f; + mask |= 1; + } + } + } + + if (coverageInvert) + { + mask = ~mask; + } + } + else + { + mask = 0xFFFFFFFF; + } + error = setBlendState(framebufferObject, data.state->getBlendState(), data.state->getBlendColor(), mask); + if (error.isError()) + { + return error; + } + + error = setDepthStencilState(data.state->getDepthStencilState(), data.state->getStencilRef(), + data.state->getStencilBackRef(), rasterizer.frontFace == GL_CCW); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +bool RendererD3D::applyTransformFeedbackBuffers(const gl::Data &data) +{ + gl::TransformFeedback *curTransformFeedback = data.state->getCurrentTransformFeedback(); + if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused()) + { + applyTransformFeedbackBuffers(*data.state); + return true; + } + else + { + return false; + } +} + +// Applies the shaders and shader constants to the Direct3D device +gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedbackActive) +{ + gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); + + gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]; + gl::VertexFormat::GetInputLayout(inputLayout, programBinary, *data.state); + + const gl::Framebuffer *fbo = data.state->getDrawFramebuffer(); + + gl::Error error = applyShaders(programBinary, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive); + if (error.isError()) + { + return error; + } + + return programBinary->applyUniforms(); +} + +// For each Direct3D sampler of either the pixel or vertex stage, +// looks up the corresponding OpenGL texture image unit and texture type, +// and sets the texture and its addressing/filtering state (or NULL when inactive). +gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount) +{ + gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary(); + + size_t samplerRange = programBinary->getUsedSamplerRange(shaderType); + for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) + { + GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex); + GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, *data.caps); + if (textureUnit != -1) + { + gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); + ASSERT(texture); + gl::SamplerState sampler = texture->getSamplerState(); + + gl::Sampler *samplerObject = data.state->getSampler(textureUnit); + if (samplerObject) + { + samplerObject->getState(&sampler); + } + + // TODO: std::binary_search may become unavailable using older versions of GCC + if (texture->isSamplerComplete(sampler, *data.textureCaps, *data.extensions, data.clientVersion) && + !std::binary_search(framebufferSerials.begin(), framebufferSerials.begin() + framebufferSerialCount, texture->getTextureSerial())) + { + gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler); + if (error.isError()) + { + return error; + } + + error = setTexture(shaderType, samplerIndex, texture); + if (error.isError()) + { + return error; + } + } + else + { + // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. + gl::Texture *incompleteTexture = getIncompleteTexture(textureType); + gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture); + if (error.isError()) + { + return error; + } + } + } + else + { + // No texture bound to this slot even though it is used by the shader, bind a NULL texture + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + } + + // Set all the remaining textures to NULL + size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits + : data.caps->maxVertexTextureImageUnits; + for (size_t samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++) + { + gl::Error error = setTexture(shaderType, samplerIndex, NULL); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::applyTextures(const gl::Data &data) +{ + FramebufferTextureSerialArray framebufferSerials; + size_t framebufferSerialCount = getBoundFramebufferTextureSerials(data, &framebufferSerials); + + gl::Error error = applyTextures(data, gl::SAMPLER_VERTEX, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + error = applyTextures(data, gl::SAMPLER_PIXEL, framebufferSerials, framebufferSerialCount); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::applyUniformBuffers(const gl::Data &data) +{ + gl::Program *programObject = data.resourceManager->getProgram(data.state->getCurrentProgramId()); + gl::ProgramBinary *programBinary = programObject->getProgramBinary(); + + std::vector boundBuffers; + + for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++) + { + GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex); + + if (data.state->getIndexedUniformBuffer(blockBinding)->id() == 0) + { + // undefined behaviour + return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to have a used but unbound uniform buffer."); + } + else + { + gl::Buffer *uniformBuffer = data.state->getIndexedUniformBuffer(blockBinding); + ASSERT(uniformBuffer); + boundBuffers.push_back(uniformBuffer); + } + } + + return programBinary->applyUniformBuffers(boundBuffers, *data.caps); +} + +bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode) +{ + if (drawMode == GL_POINTS) + { + // ProgramBinary assumes non-point rendering if gl_PointSize isn't written, + // which affects varying interpolation. Since the value of gl_PointSize is + // undefined when not written, just skip drawing to avoid unexpected results. + if (!data.state->getCurrentProgramBinary()->usesPointSize()) + { + // This is stictly speaking not an error, but developers should be + // notified of risking undefined behavior. + ERR("Point rendering without writing to gl_PointSize."); + + return true; + } + } + else if (gl::IsTriangleMode(drawMode)) + { + if (data.state->getRasterizerState().cullFace && data.state->getRasterizerState().cullMode == GL_FRONT_AND_BACK) + { + return true; + } + } + + return false; +} + +void RendererD3D::markTransformFeedbackUsage(const gl::Data &data) +{ + for (size_t i = 0; i < data.caps->maxTransformFeedbackSeparateAttributes; i++) + { + gl::Buffer *buffer = data.state->getIndexedTransformFeedbackBuffer(i); + if (buffer) + { + buffer->markTransformFeedbackUsage(); + } + } +} + +size_t RendererD3D::getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray) +{ + size_t serialCount = 0; + + const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); + for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++) + { + gl::FramebufferAttachment *attachment = drawFramebuffer->getColorbuffer(i); + if (attachment && attachment->isTexture()) + { + gl::Texture *texture = attachment->getTexture(); + (*outSerialArray)[serialCount++] = texture->getTextureSerial(); + } + } + + gl::FramebufferAttachment *depthStencilAttachment = drawFramebuffer->getDepthOrStencilbuffer(); + if (depthStencilAttachment && depthStencilAttachment->isTexture()) + { + gl::Texture *depthStencilTexture = depthStencilAttachment->getTexture(); + (*outSerialArray)[serialCount++] = depthStencilTexture->getTextureSerial(); + } + + std::sort(outSerialArray->begin(), outSerialArray->begin() + serialCount); + + return serialCount; +} + +gl::Texture *RendererD3D::getIncompleteTexture(GLenum type) +{ + if (mIncompleteTextures.find(type) == mIncompleteTextures.end()) + { + const GLubyte color[] = { 0, 0, 0, 255 }; + const gl::PixelUnpackState incompleteUnpackState(1); + + gl::Texture* t = NULL; + switch (type) + { + default: + UNREACHABLE(); + // default falls through to TEXTURE_2D + + case GL_TEXTURE_2D: + { + gl::Texture2D *incomplete2d = new gl::Texture2D(createTexture(GL_TEXTURE_2D), gl::Texture::INCOMPLETE_TEXTURE_ID); + incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + t = incomplete2d; + } + break; + + case GL_TEXTURE_CUBE_MAP: + { + gl::TextureCubeMap *incompleteCube = new gl::TextureCubeMap(createTexture(GL_TEXTURE_CUBE_MAP), gl::Texture::INCOMPLETE_TEXTURE_ID); + + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + incompleteCube->setImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incompleteCube; + } + break; + + case GL_TEXTURE_3D: + { + gl::Texture3D *incomplete3d = new gl::Texture3D(createTexture(GL_TEXTURE_3D), gl::Texture::INCOMPLETE_TEXTURE_ID); + incomplete3d->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete3d; + } + break; + + case GL_TEXTURE_2D_ARRAY: + { + gl::Texture2DArray *incomplete2darray = new gl::Texture2DArray(createTexture(GL_TEXTURE_2D_ARRAY), gl::Texture::INCOMPLETE_TEXTURE_ID); + incomplete2darray->setImage(0, 1, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, incompleteUnpackState, color); + + t = incomplete2darray; + } + break; + } + + mIncompleteTextures[type].set(t); + } + + return mIncompleteTextures[type].get(); +} + +gl::Error RendererD3D::clear(const gl::Data &data, GLbitfield mask) +{ + gl::ClearParameters clearParams = data.state->getClearParameters(mask); + + // Clips the clear to the scissor rectangle but not the viewport + gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); + if (error.isError()) + { + return error; + } + + return clear(clearParams, data.state->getDrawFramebuffer()); +} + +gl::Error RendererD3D::clearBufferfv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLfloat *values) +{ + // glClearBufferfv can be called to clear the color buffer or depth buffer + gl::ClearParameters clearParams = data.state->getClearParameters(0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorFClearValue = gl::ColorF(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_FLOAT; + } + + if (buffer == GL_DEPTH) + { + clearParams.clearDepth = true; + clearParams.depthClearValue = values[0]; + } + + // Clips the clear to the scissor rectangle but not the viewport + gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); + if (error.isError()) + { + return error; + } + + return clear(clearParams, data.state->getDrawFramebuffer()); +} + +gl::Error RendererD3D::clearBufferuiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLuint *values) +{ + // glClearBufferuiv can only be called to clear a color buffer + gl::ClearParameters clearParams = data.state->getClearParameters(0); + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorUIClearValue = gl::ColorUI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_UNSIGNED_INT; + + // Clips the clear to the scissor rectangle but not the viewport + gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); + if (error.isError()) + { + return error; + } + + return clear(clearParams, data.state->getDrawFramebuffer()); +} + +gl::Error RendererD3D::clearBufferiv(const gl::Data &data, GLenum buffer, GLint drawbuffer, const GLint *values) +{ + // glClearBufferiv can be called to clear the color buffer or stencil buffer + gl::ClearParameters clearParams = data.state->getClearParameters(0); + + if (buffer == GL_COLOR) + { + for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++) + { + clearParams.clearColor[i] = (drawbuffer == static_cast(i)); + } + clearParams.colorIClearValue = gl::ColorI(values[0], values[1], values[2], values[3]); + clearParams.colorClearType = GL_INT; + } + + if (buffer == GL_STENCIL) + { + clearParams.clearStencil = true; + clearParams.stencilClearValue = values[1]; + } + + // Clips the clear to the scissor rectangle but not the viewport + gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); + if (error.isError()) + { + return error; + } + + return clear(clearParams, data.state->getDrawFramebuffer()); +} + +gl::Error RendererD3D::clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, + GLfloat depth, GLint stencil) +{ + if (data.state->isRasterizerDiscardEnabled()) + { + return gl::Error(GL_NO_ERROR); + } + + // glClearBufferfi can only be called to clear a depth stencil buffer + gl::ClearParameters clearParams = data.state->getClearParameters(0); + clearParams.clearDepth = true; + clearParams.depthClearValue = depth; + clearParams.clearStencil = true; + clearParams.stencilClearValue = stencil; + + // Clips the clear to the scissor rectangle but not the viewport + gl::Error error = applyRenderTarget(data, GL_TRIANGLES, true); + if (error.isError()) + { + return error; + } + + return clear(clearParams, data.state->getDrawFramebuffer()); +} + +gl::Error RendererD3D::blitFramebuffer(const gl::Data &data, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + const gl::Framebuffer *readFramebuffer = data.state->getReadFramebuffer(); + const gl::Framebuffer *drawFramebuffer = data.state->getDrawFramebuffer(); + + bool blitRenderTarget = false; + bool blitDepth = false; + bool blitStencil = false; + if ((mask & GL_COLOR_BUFFER_BIT) && readFramebuffer->getReadColorbuffer() && drawFramebuffer->getFirstColorbuffer()) + { + blitRenderTarget = true; + } + if ((mask & GL_STENCIL_BUFFER_BIT) && readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer()) + { + blitStencil = true; + } + if ((mask & GL_DEPTH_BUFFER_BIT) && readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer()) + { + blitDepth = true; + } + + gl::Rectangle srcRect(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0); + gl::Rectangle dstRect(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0); + if (blitRenderTarget || blitDepth || blitStencil) + { + const gl::Rectangle *scissor = data.state->isScissorTestEnabled() ? &data.state->getScissor() : NULL; + gl::Error error = blitRect(readFramebuffer, srcRect, drawFramebuffer, dstRect, scissor, + blitRenderTarget, blitDepth, blitStencil, filter); + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error RendererD3D::readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) +{ + const gl::Framebuffer *framebuffer = data.state->getReadFramebuffer(); + + GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, type); + const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(sizedInternalFormat); + GLuint outputPitch = sizedFormatInfo.computeRowPitch(type, width, data.state->getPackAlignment()); + + return readPixels(framebuffer, x, y, width, height, format, type, outputPitch, data.state->getPackState(), + reinterpret_cast(pixels)); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h new file mode 100644 index 0000000000..9919207667 --- /dev/null +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.h @@ -0,0 +1,195 @@ + +// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// RendererD3D.h: Defines a back-end specific class for the DirectX renderer. + +#ifndef LIBGLESV2_RENDERER_RENDERERD3D_H_ +#define LIBGLESV2_RENDERER_RENDERERD3D_H_ + +#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/Data.h" + +//FIXME(jmadill): std::array is currently prohibited by Chromium style guide +#include + +namespace gl +{ +class InfoLog; +struct LinkedVarying; +class Texture; +} + +namespace rx +{ +class TextureStorage; +class VertexBuffer; +class IndexBuffer; +class ShaderExecutable; +class SwapChain; +class RenderTarget; +class Image; +class TextureStorage; +class UniformStorage; + +class RendererD3D : public Renderer +{ + public: + explicit RendererD3D(egl::Display *display); + virtual ~RendererD3D(); + + static RendererD3D *makeRendererD3D(Renderer *renderer); + + gl::Error drawArrays(const gl::Data &data, + GLenum mode, GLint first, + GLsizei count, GLsizei instances) override; + + gl::Error drawElements(const gl::Data &data, + GLenum mode, GLsizei count, GLenum type, + const GLvoid *indices, GLsizei instances, + const RangeUI &indexRange) override; + + gl::Error clear(const gl::Data &data, GLbitfield mask) override; + gl::Error clearBufferfv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLfloat *values) override; + gl::Error clearBufferuiv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLuint *values) override; + gl::Error clearBufferiv(const gl::Data &data, GLenum buffer, int drawbuffer, const GLint *values) override; + gl::Error clearBufferfi(const gl::Data &data, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) override; + + gl::Error readPixels(const gl::Data &data, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, GLsizei *bufSize, void* pixels) override; + + gl::Error blitFramebuffer(const gl::Data &data, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) override; + + // Direct3D Specific methods + virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; + + virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler) = 0; + virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture) = 0; + + virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]) = 0; + + virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState) = 0; + virtual gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) = 0; + virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, + int stencilBackRef, bool frontFaceCCW) = 0; + + virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled) = 0; + virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, + bool ignoreViewport) = 0; + + virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0; + virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, + bool rasterizerDiscard, bool transformFeedbackActive) = 0; + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) = 0; + virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0; + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) = 0; + virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0; + virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0; + + virtual void markAllStateDirty() = 0; + + virtual unsigned int getReservedVertexUniformVectors() const = 0; + virtual unsigned int getReservedFragmentUniformVectors() const = 0; + virtual unsigned int getReservedVertexUniformBuffers() const = 0; + virtual unsigned int getReservedFragmentUniformBuffers() const = 0; + virtual bool getShareHandleSupport() const = 0; + virtual bool getPostSubBufferSupport() const = 0; + + // Pixel operations + virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) = 0; + virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; + virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) = 0; + + virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) = 0; + + // RenderTarget creation + virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) = 0; + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) = 0; + + // Shader operations + virtual void releaseShaderCompiler() = 0; + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) = 0; + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) = 0; + virtual UniformStorage *createUniformStorage(size_t storageSize) = 0; + + // Image operations + virtual Image *createImage() = 0; + virtual gl::Error generateMipmap(Image *dest, Image *source) = 0; + virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0; + virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0; + virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0; + virtual TextureStorage *createTextureStorage3D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + virtual TextureStorage *createTextureStorage2DArray(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) = 0; + + // Buffer-to-texture and Texture-to-buffer copies + virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const = 0; + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) = 0; + + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const = 0; + virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const = 0; + + virtual VertexBuffer *createVertexBuffer() = 0; + virtual IndexBuffer *createIndexBuffer() = 0; + + protected: + virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0; + virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, + gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0; + virtual gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) = 0; + virtual gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, + const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, + bool blitDepth, bool blitStencil, GLenum filter) = 0; + + egl::Display *mDisplay; + + private: + DISALLOW_COPY_AND_ASSIGN(RendererD3D); + + //FIXME(jmadill): std::array is currently prohibited by Chromium style guide + typedef std::array FramebufferTextureSerialArray; + + gl::Error generateSwizzles(const gl::Data &data, gl::SamplerType type); + gl::Error generateSwizzles(const gl::Data &data); + + gl::Error applyRenderTarget(const gl::Data &data, GLenum drawMode, bool ignoreViewport); + gl::Error applyState(const gl::Data &data, GLenum drawMode); + bool applyTransformFeedbackBuffers(const gl::Data &data); + gl::Error applyShaders(const gl::Data &data, bool transformFeedbackActive); + gl::Error applyTextures(const gl::Data &data, gl::SamplerType shaderType, + const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount); + gl::Error applyTextures(const gl::Data &data); + gl::Error applyUniformBuffers(const gl::Data &data); + + bool skipDraw(const gl::Data &data, GLenum drawMode); + void markTransformFeedbackUsage(const gl::Data &data); + + size_t getBoundFramebufferTextureSerials(const gl::Data &data, + FramebufferTextureSerialArray *outSerialArray); + gl::Texture *getIncompleteTexture(GLenum type); + + gl::TextureMap mIncompleteTextures; +}; + +} + +#endif // LIBGLESV2_RENDERER_RENDERERD3D_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp index c472113eba..8a97579e16 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.cpp @@ -6,13 +6,36 @@ // ShaderD3D.cpp: Defines the rx::ShaderD3D class which implements rx::ShaderImpl. -#include "libGLESv2/renderer/d3d/ShaderD3D.h" -#include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/Shader.h" #include "libGLESv2/main.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" +#include "libGLESv2/renderer/d3d/ShaderD3D.h" +#include "common/features.h" #include "common/utilities.h" +// Definitions local to the translation unit +namespace +{ + +const char *GetShaderTypeString(GLenum type) +{ + switch (type) + { + case GL_VERTEX_SHADER: + return "VERTEX"; + + case GL_FRAGMENT_SHADER: + return "FRAGMENT"; + + default: + UNREACHABLE(); + return ""; + } +} + +} + namespace rx { @@ -44,13 +67,13 @@ const std::vector *GetShaderVariables(const std::vector *variableLis return variableList; } -ShaderD3D::ShaderD3D(GLenum type, rx::Renderer *renderer) +ShaderD3D::ShaderD3D(const gl::Data &data, GLenum type, RendererD3D *renderer) : mType(type), mRenderer(renderer), mShaderVersion(100) { uncompile(); - initializeCompiler(); + initializeCompiler(data); } ShaderD3D::~ShaderD3D() @@ -69,23 +92,28 @@ const ShaderD3D *ShaderD3D::makeShaderD3D(const ShaderImpl *impl) return static_cast(impl); } +std::string ShaderD3D::getDebugInfo() const +{ + return mDebugInfo + std::string("\n// ") + GetShaderTypeString(mType) + " SHADER END\n"; +} + // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) -void ShaderD3D::initializeCompiler() +void ShaderD3D::initializeCompiler(const gl::Data &data) { if (!mFragmentCompiler) { - int result = ShInitialize(); + bool result = ShInitialize(); if (result) { + ShShaderSpec specVersion = (data.clientVersion >= 3) ? SH_GLES3_SPEC : SH_GLES2_SPEC; ShShaderOutput hlslVersion = (mRenderer->getMajorShaderModel() >= 4) ? SH_HLSL11_OUTPUT : SH_HLSL9_OUTPUT; ShBuiltInResources resources; ShInitBuiltInResources(&resources); - // TODO(geofflang): use context's caps - const gl::Caps &caps = mRenderer->getRendererCaps(); - const gl::Extensions &extensions = mRenderer->getRendererExtensions(); + const gl::Caps &caps = *data.caps; + const gl::Extensions &extensions = *data.extensions; resources.MaxVertexAttribs = caps.maxVertexAttributes; resources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; @@ -107,8 +135,8 @@ void ShaderD3D::initializeCompiler() resources.MinProgramTexelOffset = caps.minProgramTexelOffset; resources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; - mFragmentCompiler = ShConstructCompiler(GL_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); - mVertexCompiler = ShConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources); + mFragmentCompiler = ShConstructCompiler(GL_FRAGMENT_SHADER, specVersion, hlslVersion, &resources); + mVertexCompiler = ShConstructCompiler(GL_VERTEX_SHADER, specVersion, hlslVersion, &resources); } } } @@ -126,7 +154,7 @@ void ShaderD3D::releaseCompiler() void ShaderD3D::parseVaryings(void *compiler) { - if (!mHlsl.empty()) + if (!mHlsl.empty()) { const std::vector *varyings = ShGetVaryings(compiler); ASSERT(varyings); @@ -183,21 +211,25 @@ void ShaderD3D::uncompile() mInterfaceBlocks.clear(); mActiveAttributes.clear(); mActiveOutputVariables.clear(); + mDebugInfo.clear(); } -void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) +void ShaderD3D::compileToHLSL(const gl::Data &data, void *compiler, const std::string &source) { // ensure the compiler is loaded - initializeCompiler(); + initializeCompiler(data); int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES); std::string sourcePath; + +#if !defined (ANGLE_ENABLE_WINDOWS_STORE) if (gl::perfActive()) { sourcePath = getTempPath(); writeFile(sourcePath.c_str(), source.c_str(), source.length()); compileOptions |= SH_LINE_DIRECTIVES; } +#endif int result; if (sourcePath.empty()) @@ -220,25 +252,20 @@ void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) result = ShCompile(compiler, sourceStrings, ArraySize(sourceStrings), compileOptions | SH_SOURCE_PATH); } - size_t shaderVersion = 100; - ShGetInfo(compiler, SH_SHADER_VERSION, &shaderVersion); + mShaderVersion = ShGetShaderVersion(compiler); - mShaderVersion = static_cast(shaderVersion); - - if (shaderVersion == 300 && mRenderer->getCurrentClientVersion() < 3) + if (mShaderVersion == 300 && data.clientVersion < 3) { mInfoLog = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts"; TRACE("\n%s", mInfoLog.c_str()); } else if (result) { - size_t objCodeLen = 0; - ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen); - - char* outputHLSL = new char[objCodeLen]; - ShGetObjectCode(compiler, outputHLSL); + mHlsl = ShGetObjectCode(compiler); #ifdef _DEBUG + // Prefix hlsl shader with commented out glsl shader + // Useful in diagnostics tools like pix which capture the hlsl shaders std::ostringstream hlslStream; hlslStream << "// GLSL\n"; hlslStream << "//\n"; @@ -254,14 +281,10 @@ void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1); } hlslStream << "\n\n"; - hlslStream << outputHLSL; + hlslStream << mHlsl; mHlsl = hlslStream.str(); -#else - mHlsl = outputHLSL; #endif - SafeDeleteArray(outputHLSL); - mUniforms = *GetShaderVariables(ShGetUniforms(compiler)); for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++) @@ -271,7 +294,7 @@ void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) if (uniform.staticUse) { unsigned int index = -1; - bool result = ShGetUniformRegister(compiler, uniform.name.c_str(), &index); + bool result = ShGetUniformRegister(compiler, uniform.name, &index); UNUSED_ASSERTION_VARIABLE(result); ASSERT(result); @@ -288,7 +311,7 @@ void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) if (interfaceBlock.staticUse) { unsigned int index = -1; - bool result = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name.c_str(), &index); + bool result = ShGetInterfaceBlockRegister(compiler, interfaceBlock.name, &index); UNUSED_ASSERTION_VARIABLE(result); ASSERT(result); @@ -298,24 +321,19 @@ void ShaderD3D::compileToHLSL(void *compiler, const std::string &source) } else { - size_t infoLogLen = 0; - ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen); - - char* infoLog = new char[infoLogLen]; - ShGetInfoLog(compiler, infoLog); - mInfoLog = infoLog; + mInfoLog = ShGetInfoLog(compiler); TRACE("\n%s", mInfoLog.c_str()); } } -rx::D3DWorkaroundType ShaderD3D::getD3DWorkarounds() const +D3DWorkaroundType ShaderD3D::getD3DWorkarounds() const { if (mUsesDiscardRewriting) { // ANGLE issue 486: // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization - return rx::ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION; + return ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION; } if (mUsesNestedBreak) @@ -323,10 +341,10 @@ rx::D3DWorkaroundType ShaderD3D::getD3DWorkarounds() const // ANGLE issue 603: // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence - return rx::ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION; + return ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION; } - return rx::ANGLE_D3D_WORKAROUND_NONE; + return ANGLE_D3D_WORKAROUND_NONE; } // true if varying x has a higher priority in packing than y @@ -387,19 +405,16 @@ ShShaderOutput ShaderD3D::getCompilerOutputType(GLenum shader) default: UNREACHABLE(); return SH_HLSL9_OUTPUT; } - size_t outputType = 0; - ShGetInfo(compiler, SH_OUTPUT_TYPE, &outputType); - - return static_cast(outputType); + return ShGetShaderOutputType(compiler); } -bool ShaderD3D::compile(const std::string &source) +bool ShaderD3D::compile(const gl::Data &data, const std::string &source) { uncompile(); void *compiler = getCompiler(); - compileToHLSL(compiler, source); + compileToHLSL(data, compiler, source); if (mType == GL_VERTEX_SHADER) { @@ -420,6 +435,15 @@ bool ShaderD3D::compile(const std::string &source) } } +#if ANGLE_SHADER_DEBUG_INFO == ANGLE_ENABLED + mDebugInfo += std::string("// ") + GetShaderTypeString(mType) + " SHADER BEGIN\n"; + mDebugInfo += "\n// GLSL BEGIN\n\n" + source + "\n\n// GLSL END\n\n\n"; + mDebugInfo += "// INITIAL HLSL BEGIN\n\n" + getTranslatedSource() + "\n// INITIAL HLSL END\n\n\n"; + // Successive steps will append more info +#else + mDebugInfo += getTranslatedSource(); +#endif + return !getTranslatedSource().empty(); } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h index 40e64cf36c..3c9aac2c12 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/ShaderD3D.h @@ -10,6 +10,7 @@ #define LIBGLESV2_RENDERER_SHADERD3D_H_ #include "libGLESv2/renderer/ShaderImpl.h" +#include "libGLESv2/renderer/Workarounds.h" #include "libGLESv2/Shader.h" #include @@ -17,22 +18,23 @@ namespace rx { class DynamicHLSL; -class Renderer; +class RendererD3D; class ShaderD3D : public ShaderImpl { friend class DynamicHLSL; public: - ShaderD3D(GLenum type, rx::Renderer *renderer); + ShaderD3D(const gl::Data &data, GLenum type, RendererD3D *renderer); virtual ~ShaderD3D(); static ShaderD3D *makeShaderD3D(ShaderImpl *impl); static const ShaderD3D *makeShaderD3D(const ShaderImpl *impl); // ShaderImpl implementation - const std::string &getInfoLog() const { return mInfoLog; } - const std::string &getTranslatedSource() const { return mHlsl; } + virtual const std::string &getInfoLog() const { return mInfoLog; } + virtual const std::string &getTranslatedSource() const { return mHlsl; } + virtual std::string getDebugInfo() const; // D3D-specific methods virtual void uncompile(); @@ -40,8 +42,9 @@ class ShaderD3D : public ShaderImpl unsigned int getUniformRegister(const std::string &uniformName) const; unsigned int getInterfaceBlockRegister(const std::string &blockName) const; int getSemanticIndex(const std::string &attributeName) const; + void appendDebugInfo(const std::string &info) { mDebugInfo += info; } - rx::D3DWorkaroundType getD3DWorkarounds() const; + D3DWorkaroundType getD3DWorkarounds() const; int getShaderVersion() const { return mShaderVersion; } bool usesDepthRange() const { return mUsesDepthRange; } bool usesPointSize() const { return mUsesPointSize; } @@ -49,15 +52,15 @@ class ShaderD3D : public ShaderImpl static void releaseCompiler(); static ShShaderOutput getCompilerOutputType(GLenum shader); - virtual bool compile(const std::string &source); + virtual bool compile(const gl::Data &data, const std::string &source); private: DISALLOW_COPY_AND_ASSIGN(ShaderD3D); - void compileToHLSL(void *compiler, const std::string &source); + void compileToHLSL(const gl::Data &data, void *compiler, const std::string &source); void parseVaryings(void *compiler); - void initializeCompiler(); + void initializeCompiler(const gl::Data &data); void parseAttributes(void *compiler); void *getCompiler(); @@ -67,7 +70,7 @@ class ShaderD3D : public ShaderImpl static void *mVertexCompiler; GLenum mType; - rx::Renderer *mRenderer; + RendererD3D *mRenderer; int mShaderVersion; @@ -85,6 +88,7 @@ class ShaderD3D : public ShaderImpl std::string mHlsl; std::string mInfoLog; + std::string mDebugInfo; std::map mUniformRegisterMap; std::map mInterfaceBlockRegisterMap; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp index 96c84977cb..4a67701fdf 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp @@ -6,9 +6,6 @@ // TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends. -#include "libGLESv2/renderer/d3d/TextureD3D.h" -#include "libGLESv2/renderer/d3d/TextureStorage.h" -#include "libGLESv2/renderer/d3d/ImageD3D.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Framebuffer.h" #include "libGLESv2/Texture.h" @@ -16,7 +13,11 @@ #include "libGLESv2/formatutils.h" #include "libGLESv2/renderer/BufferImpl.h" #include "libGLESv2/renderer/RenderTarget.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/BufferD3D.h" +#include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/d3d/TextureStorage.h" +#include "libGLESv2/renderer/d3d/ImageD3D.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libEGL/Surface.h" @@ -26,16 +27,51 @@ namespace rx { +namespace +{ + +gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut) +{ + if (unpack.pixelBuffer.id() != 0) + { + // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported + gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); + ptrdiff_t offset = reinterpret_cast(pixels); + + // TODO: this is the only place outside of renderer that asks for a buffers raw data. + // This functionality should be moved into renderer and the getData method of BufferImpl removed. + BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation()); + ASSERT(bufferD3D); + const uint8_t *bufferData = NULL; + gl::Error error = bufferD3D->getData(&bufferData); + if (error.isError()) + { + return error; + } + + *pointerOut = bufferData + offset; + } + else + { + *pointerOut = static_cast(pixels); + } + + return gl::Error(GL_NO_ERROR); +} + bool IsRenderTargetUsage(GLenum usage) { return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); } -TextureD3D::TextureD3D(Renderer *renderer) +} + +TextureD3D::TextureD3D(RendererD3D *renderer) : mRenderer(renderer), mUsage(GL_NONE), mDirtyImages(true), - mImmutable(false) + mImmutable(false), + mTexStorage(NULL) { } @@ -54,13 +90,12 @@ TextureStorage *TextureD3D::getNativeTexture() // ensure the underlying texture is created initializeStorage(false); - TextureStorage *storage = getBaseLevelStorage(); - if (storage) + if (mTexStorage) { updateStorage(); } - return storage; + return mTexStorage; } GLint TextureD3D::getBaseLevelWidth() const @@ -90,50 +125,79 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const return (baseImage ? baseImage->getInternalFormat() : GL_NONE); } -void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image) +bool TextureD3D::shouldUseSetData(const Image *image) const { + if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload) + { + return false; + } + + gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat()); + + // We can only handle full updates for depth-stencil textures, so to avoid complications + // disable them entirely. + if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0) + { + return false; + } + + // TODO(jmadill): Handle compressed internal formats + return (mTexStorage && !internalFormat.compressed); +} + +gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index) +{ + Image *image = getImage(index); + ASSERT(image); + // No-op if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0) { - return; + return gl::Error(GL_NO_ERROR); } // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. - const void *pixelData = pixels; - - if (unpack.pixelBuffer.id() != 0) + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); + if (error.isError()) { - // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); - ptrdiff_t offset = reinterpret_cast(pixels); - // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. - // This functionality should be moved into renderer and the getData method of BufferImpl removed. - const void *bufferData = pixelBuffer->getImplementation()->getData(); - pixelData = static_cast(bufferData) + offset; + return error; } if (pixelData != NULL) { - image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); + gl::Error error(GL_NO_ERROR); + + if (shouldUseSetData(image)) + { + error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData); + } + else + { + error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData); + } + + if (error.isError()) + { + return error; + } + mDirtyImages = true; } + + return gl::Error(GL_NO_ERROR); } -bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index) +gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index) { - const void *pixelData = pixels; - // CPU readback & copy where direct GPU copy is not supported - if (unpack.pixelBuffer.id() != 0) + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); + if (error.isError()) { - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); - ptrdiff_t offset = reinterpret_cast(pixels); - // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. - // This functionality should be moved into renderer and the getData method of BufferImpl removed. - const void *bufferData = pixelBuffer->getImplementation()->getData(); - pixelData = static_cast(bufferData) + offset; + return error; } if (pixelData != NULL) @@ -141,32 +205,78 @@ bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei w Image *image = getImage(index); ASSERT(image); - image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData); + gl::Box region(xoffset, yoffset, zoffset, width, height, depth); + if (shouldUseSetData(image)) + { + return mTexStorage->setData(index, image, ®ion, type, unpack, pixelData); + } + + gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, + type, pixelData); + if (error.isError()) + { + return error; + } + + error = commitRegion(index, region); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } - return true; + return gl::Error(GL_NO_ERROR); } -void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image) +gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image) { - if (pixels != NULL) + // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains. + // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components. + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); + if (error.isError()) { - image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels); + return error; + } + + if (pixelData != NULL) + { + gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } + + return gl::Error(GL_NO_ERROR); } -bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const void *pixels, Image *image) +gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image) { - if (pixels != NULL) + const uint8_t *pixelData = NULL; + gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData); + if (error.isError()) { - image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels); + return error; + } + + if (pixelData != NULL) + { + gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } - return true; + return gl::Error(GL_NO_ERROR); } bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat) @@ -174,21 +284,28 @@ bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum siz return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat); } -bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget) +gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget) { + // No-op if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0) { - return true; + return gl::Error(GL_NO_ERROR); } // In order to perform the fast copy through the shader, we must have the right format, and be able // to create a render target. ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); - ptrdiff_t offset = reinterpret_cast(pixels); + uintptr_t offset = reinterpret_cast(pixels); - return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); + gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const @@ -210,10 +327,192 @@ int TextureD3D::mipLevels() const return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1; } +TextureStorage *TextureD3D::getStorage() +{ + ASSERT(mTexStorage); + return mTexStorage; +} -TextureD3D_2D::TextureD3D_2D(Renderer *renderer) - : TextureD3D(renderer), - mTexStorage(NULL) +Image *TextureD3D::getBaseLevelImage() const +{ + return getImage(getImageIndex(0, 0)); +} + +gl::Error TextureD3D::generateMipmaps() +{ + GLint mipCount = mipLevels(); + + if (mipCount == 1) + { + return gl::Error(GL_NO_ERROR); // no-op + } + + // Set up proper mipmap chain in our Image array. + initMipmapsImages(); + + // We know that all layers have the same dimension, for the texture to be complete + GLint layerCount = static_cast(getLayerCount(0)); + + // When making mipmaps with the setData workaround enabled, the texture storage has + // the image data already. For non-render-target storage, we have to pull it out into + // an image layer. + if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage) + { + if (!mTexStorage->isRenderTarget()) + { + // Copy from the storage mip 0 to Image mip 0 + for (GLint layer = 0; layer < layerCount; ++layer) + { + gl::ImageIndex srcIndex = getImageIndex(0, layer); + + Image *image = getImage(srcIndex); + gl::Rectangle area(0, 0, image->getWidth(), image->getHeight()); + gl::Error error = image->copy(0, 0, 0, area, srcIndex, mTexStorage); + if (error.isError()) + { + return error; + } + } + } + else + { + gl::Error error = updateStorage(); + if (error.isError()) + { + return error; + } + } + } + + bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget()); + + for (GLint layer = 0; layer < layerCount; ++layer) + { + for (GLint mip = 1; mip < mipCount; ++mip) + { + ASSERT(getLayerCount(mip) == layerCount); + + gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer); + gl::ImageIndex destIndex = getImageIndex(mip, layer); + + if (renderableStorage) + { + // GPU-side mipmapping + gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex); + if (error.isError()) + { + return error; + } + } + else + { + // CPU-side mipmapping + gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex)); + if (error.isError()) + { + return error; + } + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::isBaseImageZeroSize() const +{ + Image *baseImage = getBaseLevelImage(); + + if (!baseImage || baseImage->getWidth() <= 0) + { + return true; + } + + if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0) + { + return true; + } + + if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0) + { + return true; + } + + return false; +} + +gl::Error TextureD3D::ensureRenderTarget() +{ + gl::Error error = initializeStorage(true); + if (error.isError()) + { + return error; + } + + if (!isBaseImageZeroSize()) + { + ASSERT(mTexStorage); + if (!mTexStorage->isRenderTarget()) + { + TextureStorage *newRenderTargetStorage = NULL; + error = createCompleteStorage(true, &newRenderTargetStorage); + if (error.isError()) + { + return error; + } + + error = mTexStorage->copyToStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + + error = setCompleteTexStorage(newRenderTargetStorage); + if (error.isError()) + { + SafeDelete(newRenderTargetStorage); + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const +{ + Image *image = getImage(index); + bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0))); + return (image->isRenderableFormat() && levelsComplete); +} + +gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box ®ion) +{ + if (mTexStorage) + { + ASSERT(isValidIndex(index)); + Image *image = getImage(index); + ImageD3D *imageD3D = ImageD3D::makeImageD3D(image); + gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region); + if (error.isError()) + { + return error; + } + + image->markClean(); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer) + : TextureD3D(renderer) { for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) { @@ -292,7 +591,9 @@ bool TextureD3D_2D::isDepth(GLint level) const return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, + GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, + const void *pixels) { ASSERT(target == GL_TEXTURE_2D && depth == 1); @@ -302,142 +603,209 @@ void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei redefineImage(level, sizedInternalFormat, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + // Attempt a fast gpu copy of the pixel data to the surface if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level)) { - gl::ImageIndex index = gl::ImageIndex::Make2D(level); - // Will try to create RT storage if it does not exist - RenderTarget *destRenderTarget = getRenderTarget(index); + RenderTarget *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1); - if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) { - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; + return error; } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; } if (!fastUnpacked) { - TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, + GLsizei width, GLsizei height, GLsizei depth, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D && depth == 1); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly redefineImage(level, format, width, height); - TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); + return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]); } -void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); bool fastUnpacked = false; gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box destArea(xoffset, yoffset, 0, width, height, 1); if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level)) { - RenderTarget *renderTarget = getRenderTarget(index); - gl::Box destArea(xoffset, yoffset, 0, width, height, 1); - - if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget)) + RenderTarget *renderTarget = NULL; + gl::Error error = getRenderTarget(index, &renderTarget); + if (error.isError()) { - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; + return error; } + + error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; } - if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index)) + if (!fastUnpacked) { - commitRect(level, xoffset, yoffset, width, height); + return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, + unpack, pixels, index); } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0); - if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level])) + gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]); + if (error.isError()) { - commitRect(level, xoffset, yoffset, width, height); + return error; } + + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(xoffset, yoffset, 0, width, height, 1); + return commitRegion(index, region); } -void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, + gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); redefineImage(level, sizedInternalFormat, width, height); - if (!mImageArray[level]->isRenderableFormat()) + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + if (!canCreateRenderTargetForImage(index)) { - mImageArray[level]->copy(0, 0, 0, x, y, width, height, source); + gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + mImageArray[level]->markClean(); if (width != 0 && height != 0 && isValidLevel(level)) { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level); + gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D && zoffset == 0); // can only make our texture storage to a render target if level 0 is defined (with a width & height) and // the current level we're copying to is defined (with appropriate format, width & height) - bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); - if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + + if (!canCreateRenderTargetForImage(index)) { - mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source); + gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } if (isValidLevel(level)) { - updateStorageLevel(level); + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage2D(source, sourceRect, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, mTexStorage, level); + error = mRenderer->copyImage2D(source, sourceRect, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + xoffset, yoffset, mTexStorage, level); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { ASSERT(target == GL_TEXTURE_2D && depth == 1); @@ -453,11 +821,20 @@ void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true); } - mImmutable = true; - + // TODO(geofflang): Verify storage creation had no errors bool renderTarget = IsRenderTargetUsage(mUsage); TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels); - setCompleteTexStorage(storage); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); } void TextureD3D_2D::bindTexImage(egl::Surface *surface) @@ -489,7 +866,7 @@ void TextureD3D_2D::releaseTexImage() } } -void TextureD3D_2D::generateMipmaps() +void TextureD3D_2D::initMipmapsImages() { // Purge array levels 1 through q and reset them to represent the generated mipmap levels. int levelCount = mipLevels(); @@ -499,42 +876,32 @@ void TextureD3D_2D::generateMipmaps() std::max(getBaseLevelWidth() >> level, 1), std::max(getBaseLevelHeight() >> level, 1)); } - - if (mTexStorage && mTexStorage->isRenderTarget()) - { - mTexStorage->generateMipmaps(); - for (int level = 1; level < levelCount; level++) - { - mImageArray[level]->markClean(); - } - } - else - { - for (int level = 1; level < levelCount; level++) - { - mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); - } - } } unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index) { ASSERT(!index.hasLayer()); - return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); } -RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { ASSERT(!index.hasLayer()); // ensure the underlying texture is created - if (!ensureRenderTarget()) + gl::Error error = ensureRenderTarget(); + if (error.isError()) { - return NULL; + return error; } - updateStorageLevel(index.mipIndex); - return mTexStorage->getRenderTarget(index); + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); } bool TextureD3D_2D::isValidLevel(int level) const @@ -586,31 +953,55 @@ bool TextureD3D_2D::isLevelComplete(int level) const return true; } +bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + // Constructs a native texture resource from the texture images -void TextureD3D_2D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2D::initializeStorage(bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return; + return gl::Error(GL_NO_ERROR); } // do not attempt to create storage for nonexistant data if (!isLevelComplete(0)) { - return; + return gl::Error(GL_NO_ERROR); } bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); - setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + ASSERT(mTexStorage); // flush image data to the storage - updateStorage(); + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } -TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const +gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const { GLsizei width = getBaseLevelWidth(); GLsizei height = getBaseLevelHeight(); @@ -621,26 +1012,35 @@ TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const // use existing storage level count, when previously specified by TexStorage*D GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); - return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels); + // TODO(geofflang): Determine if the texture creation succeeded + *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - - if (mTexStorage && mTexStorage->isManaged()) + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { - for (int level = 0; level < mTexStorage->getLevelCount(); level++) + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - mImageArray[level]->setManagedSurface2D(mTexStorage, level); + gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level); + if (error.isError()) + { + return error; + } } } + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2D::updateStorage() +gl::Error TextureD3D_2D::updateStorage() { ASSERT(mTexStorage != NULL); GLint storageLevels = mTexStorage->getLevelCount(); @@ -648,54 +1048,34 @@ void TextureD3D_2D::updateStorage() { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - updateStorageLevel(level); - } - } -} - -bool TextureD3D_2D::ensureRenderTarget() -{ - initializeStorage(true); - - if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0) - { - ASSERT(mTexStorage); - if (!mTexStorage->isRenderTarget()) - { - TextureStorage *newRenderTargetStorage = createCompleteStorage(true); - - if (!mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage)) + gl::Error error = updateStorageLevel(level); + if (error.isError()) { - delete newRenderTargetStorage; - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } - - setCompleteTexStorage(newRenderTargetStorage); } } - return (mTexStorage && mTexStorage->isRenderTarget()); + return gl::Error(GL_NO_ERROR); } -TextureStorage *TextureD3D_2D::getBaseLevelStorage() -{ - return mTexStorage; -} - -const ImageD3D *TextureD3D_2D::getBaseLevelImage() const -{ - return mImageArray[0]; -} - -void TextureD3D_2D::updateStorageLevel(int level) +gl::Error TextureD3D_2D::updateStorageLevel(int level) { ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { - commitRect(level, 0, 0, getWidth(level), getHeight(level)); + gl::ImageIndex index = gl::ImageIndex::Make2D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height) @@ -727,22 +1107,25 @@ void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei wi } } -void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::ImageIndexIterator TextureD3D_2D::imageIterator() const { - if (isValidLevel(level)) - { - ImageD3D *image = mImageArray[level]; - if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height)) - { - image->markClean(); - } - } + return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount()); } +gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // "layer" does not apply to 2D Textures. + return gl::ImageIndex::Make2D(mip); +} -TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer) - : TextureD3D(renderer), - mTexStorage(NULL) +bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_2D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer) + : TextureD3D(renderer) { for (int i = 0; i < 6; i++) { @@ -802,19 +1185,23 @@ bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0; } -void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, + GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, + const void *pixels) { ASSERT(depth == 1); - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - redefineImage(faceIndex, level, sizedInternalFormat, width, height); + redefineImage(index.layerIndex, level, sizedInternalFormat, width, height); - TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]); + return TextureD3D::setImage(unpack, type, pixels, index); } -void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, + GLsizei width, GLsizei height, GLsizei depth, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(depth == 1); @@ -823,101 +1210,129 @@ void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum form redefineImage(faceIndex, level, format, width, height); - TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]); + return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]); } -void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(depth == 1 && zoffset == 0); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index); +} - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); +gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) +{ + ASSERT(depth == 1 && zoffset == 0); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index)) + + gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]); + if (error.isError()) { - commitRect(faceIndex, level, xoffset, yoffset, width, height); + return error; } + + gl::Box region(xoffset, yoffset, 0, width, height, 1); + return commitRegion(index, region); } -void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) -{ - ASSERT(depth == 1 && zoffset == 0); - - int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - - if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level])) - { - commitRect(faceIndex, level, xoffset, yoffset, width, height); - } -} - -void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, + GLsizei width, GLsizei height, gl::Framebuffer *source) { int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE); redefineImage(faceIndex, level, sizedInternalFormat, width, height); - if (!mImageArray[faceIndex][level]->isRenderableFormat()) + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); + + if (!canCreateRenderTargetForImage(index)) { - mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } + mImageArray[faceIndex][level]->markClean(); ASSERT(width == height); if (width > 0 && isValidFaceLevel(faceIndex, level)) { - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level); + error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target); - // We can only make our texture storage to a render target if the level we're copying *to* is complete - // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot - // rely on the "getBaseLevel*" methods reliably otherwise. - bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete(); + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + if (!canCreateRenderTargetForImage(index)) { - mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source); + gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } if (isValidFaceLevel(faceIndex, level)) { - updateStorageFaceLevel(faceIndex, level); + error = updateStorageFaceLevel(faceIndex, level); + if (error.isError()) + { + return error; + } - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, mTexStorage, target, level); + error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + xoffset, yoffset, mTexStorage, target, level); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { ASSERT(width == height); ASSERT(depth == 1); @@ -939,11 +1354,20 @@ void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalform } } - mImmutable = true; - + // TODO(geofflang): Verify storage creation had no errors bool renderTarget = IsRenderTargetUsage(mUsage); TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels); - setCompleteTexStorage(storage); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); } // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. @@ -984,7 +1408,7 @@ void TextureD3D_Cube::releaseTexImage() } -void TextureD3D_Cube::generateMipmaps() +void TextureD3D_Cube::initMipmapsImages() { // Purge array levels 1 through q and reset them to represent the generated mipmap levels. int levelCount = mipLevels(); @@ -996,74 +1420,76 @@ void TextureD3D_Cube::generateMipmaps() redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize); } } - - if (mTexStorage && mTexStorage->isRenderTarget()) - { - mTexStorage->generateMipmaps(); - - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - for (int level = 1; level < levelCount; level++) - { - mImageArray[faceIndex][level]->markClean(); - } - } - } - else - { - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - for (int level = 1; level < levelCount; level++) - { - mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]); - } - } - } } unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index) { - return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); + return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); } -RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { ASSERT(gl::IsCubemapTextureTarget(index.type)); // ensure the underlying texture is created - if (!ensureRenderTarget()) + gl::Error error = ensureRenderTarget(); + if (error.isError()) { - return NULL; + return error; } - updateStorageFaceLevel(index.layerIndex, index.mipIndex); - return mTexStorage->getRenderTarget(index); + error = updateStorageFaceLevel(index.layerIndex, index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); } -void TextureD3D_Cube::initializeStorage(bool renderTarget) +gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return; + return gl::Error(GL_NO_ERROR); } // do not attempt to create storage for nonexistant data if (!isFaceLevelComplete(0, 0)) { - return; + return gl::Error(GL_NO_ERROR); } bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage)); - setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + ASSERT(mTexStorage); // flush image data to the storage - updateStorage(); + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } -TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const +gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const { GLsizei size = getBaseLevelWidth(); @@ -1072,29 +1498,37 @@ TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const // use existing storage level count, when previously specified by TexStorage*D GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1)); - return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels); + // TODO (geofflang): detect if storage creation succeeded + *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) { - SafeDelete(mTexStorage); - mTexStorage = newCompleteTexStorage; - - if (mTexStorage && mTexStorage->isManaged()) + if (newCompleteTexStorage && newCompleteTexStorage->isManaged()) { for (int faceIndex = 0; faceIndex < 6; faceIndex++) { - for (int level = 0; level < mTexStorage->getLevelCount(); level++) + for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++) { - mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level); + gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level); + if (error.isError()) + { + return error; + } } } } + SafeDelete(mTexStorage); + mTexStorage = newCompleteTexStorage; + mDirtyImages = true; + return gl::Error(GL_NO_ERROR); } -void TextureD3D_Cube::updateStorage() +gl::Error TextureD3D_Cube::updateStorage() { ASSERT(mTexStorage != NULL); GLint storageLevels = mTexStorage->getLevelCount(); @@ -1104,46 +1538,16 @@ void TextureD3D_Cube::updateStorage() { if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level)) { - updateStorageFaceLevel(face, level); + gl::Error error = updateStorageFaceLevel(face, level); + if (error.isError()) + { + return error; + } } } } -} -bool TextureD3D_Cube::ensureRenderTarget() -{ - initializeStorage(true); - - if (getBaseLevelWidth() > 0) - { - ASSERT(mTexStorage); - if (!mTexStorage->isRenderTarget()) - { - TextureStorage *newRenderTargetStorage = createCompleteStorage(true); - - if (!mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage)) - { - delete newRenderTargetStorage; - return gl::error(GL_OUT_OF_MEMORY, false); - } - - setCompleteTexStorage(newRenderTargetStorage); - } - } - - return (mTexStorage && mTexStorage->isRenderTarget()); -} - -TextureStorage *TextureD3D_Cube::getBaseLevelStorage() -{ - return mTexStorage; -} - -const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const -{ - // Note: if we are not cube-complete, there is no single base level image that can describe all - // cube faces, so this method is only well-defined for a cube-complete base level. - return mImageArray[0][0]; + return gl::Error(GL_NO_ERROR); } bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const @@ -1191,15 +1595,29 @@ bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const return true; } -void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) +bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const +{ + return isFaceLevelComplete(index.layerIndex, index.mipIndex); +} + +gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level) { ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL); ImageD3D *image = mImageArray[faceIndex][level]; if (image->isDirty()) { - commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight()); + GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex); + gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level); + gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height) @@ -1235,20 +1653,25 @@ void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalf } } -void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const { - if (isValidFaceLevel(faceIndex, level)) - { - ImageD3D *image = mImageArray[faceIndex][level]; - if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height)) - image->markClean(); - } + return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount()); } +gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const +{ + // The "layer" of the image index corresponds to the cube face + return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip); +} -TextureD3D_3D::TextureD3D_3D(Renderer *renderer) - : TextureD3D(renderer), - mTexStorage(NULL) +bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && gl::IsCubemapTextureTarget(index.type) && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer) + : TextureD3D(renderer) { for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i) { @@ -1327,7 +1750,9 @@ bool TextureD3D_3D::isDepth(GLint level) const return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, + GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, + const void *pixels) { ASSERT(target == GL_TEXTURE_3D); GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type); @@ -1336,40 +1761,60 @@ void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei bool fastUnpacked = false; + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer if (isFastUnpackable(unpack, sizedInternalFormat)) { // Will try to create RT storage if it does not exist - gl::ImageIndex index = gl::ImageIndex::Make3D(level); - RenderTarget *destRenderTarget = getRenderTarget(index); + RenderTarget *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); - if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget)) + error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget); + if (error.isError()) { - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; + return error; } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; } if (!fastUnpacked) { - TextureD3D::setImage(unpack, type, pixels, mImageArray[level]); + gl::Error error = TextureD3D::setImage(unpack, type, pixels, index); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, + GLsizei width, GLsizei height,GLsizei depth, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_3D); // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly redefineImage(level, format, width, height, depth); - TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]); + return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]); } -void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_3D); @@ -1380,74 +1825,108 @@ void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yo // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer if (isFastUnpackable(unpack, getInternalFormat(level))) { - RenderTarget *destRenderTarget = getRenderTarget(index); - gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); - - if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget)) + RenderTarget *destRenderTarget = NULL; + gl::Error error = getRenderTarget(index, &destRenderTarget); + if (error.isError()) { - // Ensure we don't overwrite our newly initialized data - mImageArray[level]->markClean(); - - fastUnpacked = true; + return error; } + + gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth); + error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget); + if (error.isError()) + { + return error; + } + + // Ensure we don't overwrite our newly initialized data + mImageArray[level]->markClean(); + + fastUnpacked = true; } - if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index)) + if (!fastUnpacked) { - commitRect(level, xoffset, yoffset, zoffset, width, height, depth); + return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, + unpack, pixels, index); } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_3D); - if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level])) + gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, + format, imageSize, unpack, pixels, mImageArray[level]); + if (error.isError()) { - commitRect(level, xoffset, yoffset, zoffset, width, height, depth); + return error; } + + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(xoffset, yoffset, zoffset, width, height, depth); + return commitRegion(index, region); } -void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, + GLsizei width, GLsizei height, gl::Framebuffer *source) { UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented."); } -void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_3D); - // can only make our texture storage to a render target if level 0 is defined (with a width & height) and - // the current level we're copying to is defined (with appropriate format, width & height) - bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::Make3D(level); - if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + if (canCreateRenderTargetForImage(index)) { - mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source); + gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } if (isValidLevel(level)) { - updateStorageLevel(level); + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage3D(source, sourceRect, - gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, - xoffset, yoffset, zoffset, mTexStorage, level); + error = mRenderer->copyImage3D(source, sourceRect, + gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format, + xoffset, yoffset, zoffset, mTexStorage, level); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { ASSERT(target == GL_TEXTURE_3D); @@ -1464,11 +1943,20 @@ void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true); } - mImmutable = true; - + // TODO(geofflang): Verify storage creation had no errors bool renderTarget = IsRenderTargetUsage(mUsage); TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels); - setCompleteTexStorage(storage); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); } void TextureD3D_3D::bindTexImage(egl::Surface *surface) @@ -1482,7 +1970,7 @@ void TextureD3D_3D::releaseTexImage() } -void TextureD3D_3D::generateMipmaps() +void TextureD3D_3D::initMipmapsImages() { // Purge array levels 1 through q and reset them to represent the generated mipmap levels. int levelCount = mipLevels(); @@ -1493,74 +1981,85 @@ void TextureD3D_3D::generateMipmaps() std::max(getBaseLevelHeight() >> level, 1), std::max(getBaseLevelDepth() >> level, 1)); } - - if (mTexStorage && mTexStorage->isRenderTarget()) - { - mTexStorage->generateMipmaps(); - - for (int level = 1; level < levelCount; level++) - { - mImageArray[level]->markClean(); - } - } - else - { - for (int level = 1; level < levelCount; level++) - { - mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]); - } - } } unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index) { - return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); } -RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { // ensure the underlying texture is created - if (!ensureRenderTarget()) + gl::Error error = ensureRenderTarget(); + if (error.isError()) { - return NULL; + return error; } if (index.hasLayer()) { - updateStorage(); + error = updateStorage(); + if (error.isError()) + { + return error; + } } else { - updateStorageLevel(index.mipIndex); + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } } - return mTexStorage->getRenderTarget(index); + return mTexStorage->getRenderTarget(index, outRT); } -void TextureD3D_3D::initializeStorage(bool renderTarget) +gl::Error TextureD3D_3D::initializeStorage(bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return; + return gl::Error(GL_NO_ERROR); } // do not attempt to create storage for nonexistant data if (!isLevelComplete(0)) { - return; + return gl::Error(GL_NO_ERROR); } bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + ASSERT(mTexStorage); // flush image data to the storage - updateStorage(); + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } -TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const +gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const { GLsizei width = getBaseLevelWidth(); GLsizei height = getBaseLevelHeight(); @@ -1572,10 +2071,13 @@ TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const // use existing storage level count, when previously specified by TexStorage*D GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth)); - return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + // TODO: Verify creation of the storage succeeded + *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) { SafeDelete(mTexStorage); mTexStorage = newCompleteTexStorage; @@ -1583,9 +2085,11 @@ void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) // We do not support managed 3D storage, as that is D3D9/ES2-only ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_3D::updateStorage() +gl::Error TextureD3D_3D::updateStorage() { ASSERT(mTexStorage != NULL); GLint storageLevels = mTexStorage->getLevelCount(); @@ -1593,43 +2097,15 @@ void TextureD3D_3D::updateStorage() { if (mImageArray[level]->isDirty() && isLevelComplete(level)) { - updateStorageLevel(level); - } - } -} - -bool TextureD3D_3D::ensureRenderTarget() -{ - initializeStorage(true); - - if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0) - { - ASSERT(mTexStorage); - if (!mTexStorage->isRenderTarget()) - { - TextureStorage *newRenderTargetStorage = createCompleteStorage(true); - - if (!mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage)) + gl::Error error = updateStorageLevel(level); + if (error.isError()) { - delete newRenderTargetStorage; - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } - - setCompleteTexStorage(newRenderTargetStorage); } } - return (mTexStorage && mTexStorage->isRenderTarget()); -} - -TextureStorage *TextureD3D_3D::getBaseLevelStorage() -{ - return mTexStorage; -} - -const ImageD3D *TextureD3D_3D::getBaseLevelImage() const -{ - return mImageArray[0]; + return gl::Error(GL_NO_ERROR); } bool TextureD3D_3D::isValidLevel(int level) const @@ -1685,15 +2161,28 @@ bool TextureD3D_3D::isLevelComplete(int level) const return true; } -void TextureD3D_3D::updateStorageLevel(int level) +bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_3D::updateStorageLevel(int level) { ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL); ASSERT(isLevelComplete(level)); if (mImageArray[level]->isDirty()) { - commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + gl::ImageIndex index = gl::ImageIndex::Make3D(level); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level)); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) @@ -1727,22 +2216,26 @@ void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei wi } } -void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) +gl::ImageIndexIterator TextureD3D_3D::imageIterator() const { - if (isValidLevel(level)) - { - ImageD3D *image = mImageArray[level]; - if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth)) - { - image->markClean(); - } - } + return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(), + gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL); } +gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const +{ + // The "layer" here does not apply to 3D images. We use one Image per mip. + return gl::ImageIndex::Make3D(mip); +} -TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer) - : TextureD3D(renderer), - mTexStorage(NULL) +bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const +{ + return (mTexStorage && index.type == GL_TEXTURE_3D && + index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount()); +} + +TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer) + : TextureD3D(renderer) { for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level) { @@ -1791,11 +2284,6 @@ GLsizei TextureD3D_2DArray::getHeight(GLint level) const return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0; } -GLsizei TextureD3D_2DArray::getLayers(GLint level) const -{ - return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0; -} - GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const { return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE; @@ -1806,7 +2294,9 @@ bool TextureD3D_2DArray::isDepth(GLint level) const return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0; } -void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, + GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, + const void *pixels) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -1820,11 +2310,20 @@ void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLs for (int i = 0; i < depth; i++) { const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i); + gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, + GLsizei width, GLsizei height, GLsizei depth, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -1837,11 +2336,19 @@ void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum f for (int i = 0; i < depth; i++) { const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]); + gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels) +gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, + const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -1854,14 +2361,20 @@ void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLi const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); - if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index)) + gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, + unpack, layerPixels, index); + if (error.isError()) { - commitRect(level, xoffset, yoffset, layer, width, height); + return error; } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels) +gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, GLenum format, + GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -1873,52 +2386,75 @@ void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xo int layer = zoffset + i; const void *layerPixels = pixels ? (reinterpret_cast(pixels) + (inputDepthPitch * i)) : NULL; - if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer])) + gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]); + if (error.isError()) { - commitRect(level, xoffset, yoffset, layer, width, height); + return error; + } + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(xoffset, yoffset, 0, width, height, 1); + error = commitRegion(index, region); + if (error.isError()) + { + return error; } } + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented."); } -void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) { ASSERT(target == GL_TEXTURE_2D_ARRAY); - // can only make our texture storage to a render target if level 0 is defined (with a width & height) and - // the current level we're copying to is defined (with appropriate format, width & height) - bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0); + gl::Rectangle sourceRect(x, y, width, height); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset); - if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget)) + if (canCreateRenderTargetForImage(index)) { - mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source); + gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source); + if (error.isError()) + { + return error; + } + mDirtyImages = true; } else { - ensureRenderTarget(); + gl::Error error = ensureRenderTarget(); + if (error.isError()) + { + return error; + } if (isValidLevel(level)) { - updateStorageLevel(level); + error = updateStorageLevel(level); + if (error.isError()) + { + return error; + } - gl::Rectangle sourceRect; - sourceRect.x = x; - sourceRect.width = width; - sourceRect.y = y; - sourceRect.height = height; - - mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format, - xoffset, yoffset, zoffset, mTexStorage, level); + error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format, + xoffset, yoffset, zoffset, mTexStorage, level); + if (error.isError()) + { + return error; + } } } + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { ASSERT(target == GL_TEXTURE_2D_ARRAY); @@ -1945,11 +2481,20 @@ void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalf } } - mImmutable = true; - + // TODO(geofflang): Verify storage creation had no errors bool renderTarget = IsRenderTargetUsage(mUsage); TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels); - setCompleteTexStorage(storage); + + gl::Error error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + + mImmutable = true; + + return gl::Error(GL_NO_ERROR); } void TextureD3D_2DArray::bindTexImage(egl::Surface *surface) @@ -1963,7 +2508,7 @@ void TextureD3D_2DArray::releaseTexImage() } -void TextureD3D_2DArray::generateMipmaps() +void TextureD3D_2DArray::initMipmapsImages() { int baseWidth = getBaseLevelWidth(); int baseHeight = getBaseLevelHeight(); @@ -1976,76 +2521,78 @@ void TextureD3D_2DArray::generateMipmaps() { redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth); } - - if (mTexStorage && mTexStorage->isRenderTarget()) - { - mTexStorage->generateMipmaps(); - - for (int level = 1; level < levelCount; level++) - { - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - mImageArray[level][layer]->markClean(); - } - } - } - else - { - for (int level = 1; level < levelCount; level++) - { - for (int layer = 0; layer < mLayerCounts[level]; layer++) - { - mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]); - } - } - } } unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index) { - return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0); + return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0); } -RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { // ensure the underlying texture is created - if (!ensureRenderTarget()) + gl::Error error = ensureRenderTarget(); + if (error.isError()) { - return NULL; + return error; } - updateStorageLevel(index.mipIndex); - return mTexStorage->getRenderTarget(index); + error = updateStorageLevel(index.mipIndex); + if (error.isError()) + { + return error; + } + + return mTexStorage->getRenderTarget(index, outRT); } -void TextureD3D_2DArray::initializeStorage(bool renderTarget) +gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget) { // Only initialize the first time this texture is used as a render target or shader resource if (mTexStorage) { - return; + return gl::Error(GL_NO_ERROR); } // do not attempt to create storage for nonexistant data if (!isLevelComplete(0)) { - return; + return gl::Error(GL_NO_ERROR); } bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - setCompleteTexStorage(createCompleteStorage(createRenderTarget)); + TextureStorage *storage = NULL; + gl::Error error = createCompleteStorage(createRenderTarget, &storage); + if (error.isError()) + { + return error; + } + + error = setCompleteTexStorage(storage); + if (error.isError()) + { + SafeDelete(storage); + return error; + } + ASSERT(mTexStorage); // flush image data to the storage - updateStorage(); + error = updateStorage(); + if (error.isError()) + { + return error; + } + + return gl::Error(GL_NO_ERROR); } -TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const +gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const { GLsizei width = getBaseLevelWidth(); GLsizei height = getBaseLevelHeight(); - GLsizei depth = getLayers(0); + GLsizei depth = getLayerCount(0); GLenum internalFormat = getBaseLevelInternalFormat(); ASSERT(width > 0 && height > 0 && depth > 0); @@ -2053,10 +2600,13 @@ TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) con // use existing storage level count, when previously specified by TexStorage*D GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1)); - return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + // TODO(geofflang): Verify storage creation succeeds + *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) +gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage) { SafeDelete(mTexStorage); mTexStorage = newCompleteTexStorage; @@ -2064,9 +2614,11 @@ void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexSto // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only ASSERT(!mTexStorage->isManaged()); + + return gl::Error(GL_NO_ERROR); } -void TextureD3D_2DArray::updateStorage() +gl::Error TextureD3D_2DArray::updateStorage() { ASSERT(mTexStorage != NULL); GLint storageLevels = mTexStorage->getLevelCount(); @@ -2074,43 +2626,15 @@ void TextureD3D_2DArray::updateStorage() { if (isLevelComplete(level)) { - updateStorageLevel(level); - } - } -} - -bool TextureD3D_2DArray::ensureRenderTarget() -{ - initializeStorage(true); - - if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0) - { - ASSERT(mTexStorage); - if (!mTexStorage->isRenderTarget()) - { - TextureStorage *newRenderTargetStorage = createCompleteStorage(true); - - if (!mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage)) + gl::Error error = updateStorageLevel(level); + if (error.isError()) { - delete newRenderTargetStorage; - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } - - setCompleteTexStorage(newRenderTargetStorage); } } - return (mTexStorage && mTexStorage->isRenderTarget()); -} - -const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const -{ - return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL); -} - -TextureStorage *TextureD3D_2DArray::getBaseLevelStorage() -{ - return mTexStorage; + return gl::Error(GL_NO_ERROR); } bool TextureD3D_2DArray::isValidLevel(int level) const @@ -2129,7 +2653,7 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const GLsizei width = getBaseLevelWidth(); GLsizei height = getBaseLevelHeight(); - GLsizei layers = getLayers(0); + GLsizei layers = getLayerCount(0); if (width <= 0 || height <= 0 || layers <= 0) { @@ -2156,7 +2680,7 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const return false; } - if (getLayers(level) != layers) + if (getLayerCount(level) != layers) { return false; } @@ -2164,7 +2688,12 @@ bool TextureD3D_2DArray::isLevelComplete(int level) const return true; } -void TextureD3D_2DArray::updateStorageLevel(int level) +bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const +{ + return isLevelComplete(index.mipIndex); +} + +gl::Error TextureD3D_2DArray::updateStorageLevel(int level) { ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts)); ASSERT(isLevelComplete(level)); @@ -2174,9 +2703,17 @@ void TextureD3D_2DArray::updateStorageLevel(int level) ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL); if (mImageArray[level][layer]->isDirty()) { - commitRect(level, 0, 0, layer, getWidth(level), getHeight(level)); + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer); + gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1); + gl::Error error = commitRegion(index, region); + if (error.isError()) + { + return error; + } } } + + return gl::Error(GL_NO_ERROR); } void TextureD3D_2DArray::deleteImages() @@ -2198,7 +2735,7 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsiz // If there currently is a corresponding storage texture image, it has these parameters const int storageWidth = std::max(1, getBaseLevelWidth() >> level); const int storageHeight = std::max(1, getBaseLevelHeight() >> level); - const int storageDepth = getLayers(0); + const int storageDepth = getLayerCount(0); const GLenum storageFormat = getBaseLevelInternalFormat(); for (int layer = 0; layer < mLayerCounts[level]; layer++) @@ -2245,16 +2782,32 @@ void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsiz } } -void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height) +gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const { - if (isValidLevel(level) && layerTarget < getLayers(level)) + return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts); +} + +gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const +{ + return gl::ImageIndex::Make2DArray(mip, layer); +} + +bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const +{ + // Check for having a storage and the right type of index + if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY) { - ImageD3D *image = mImageArray[level][layerTarget]; - if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height)) - { - image->markClean(); - } + return false; } + + // Check the mip index + if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount()) + { + return false; + } + + // Check the layer index + return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex])); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h index 41c73180de..083a6335b9 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.h @@ -11,7 +11,7 @@ #include "libGLESv2/renderer/TextureImpl.h" #include "libGLESv2/angletypes.h" -#include "libGLESv2/constants.h" +#include "libGLESv2/Constants.h" namespace gl { @@ -23,19 +23,19 @@ namespace rx class Image; class ImageD3D; -class Renderer; +class RendererD3D; class RenderTarget; class TextureStorage; class TextureD3D : public TextureImpl { public: - TextureD3D(Renderer *renderer); + TextureD3D(RendererD3D *renderer); virtual ~TextureD3D(); static TextureD3D *makeTextureD3D(TextureImpl *texture); - virtual TextureStorage *getNativeTexture(); + TextureStorage *getNativeTexture(); virtual void setUsage(GLenum usage) { mUsage = usage; } bool hasDirtyImages() const { return mDirtyImages; } @@ -48,45 +48,68 @@ class TextureD3D : public TextureImpl bool isImmutable() const { return mImmutable; } - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index) = 0; + // Returns an iterator over all "Images" for this particular Texture. + virtual gl::ImageIndexIterator imageIterator() const = 0; + + // Returns an ImageIndex for a particular "Image". 3D Textures do not have images for + // slices of their depth texures, so 3D textures ignore the layer parameter. + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0; + virtual bool isValidIndex(const gl::ImageIndex &index) const = 0; + + virtual gl::Error generateMipmaps(); + TextureStorage *getStorage(); + Image *getBaseLevelImage() const; + protected: - void setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image); - bool subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index); - void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image); - bool subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const void *pixels, Image *image); + gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index); + gl::Error subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index); + gl::Error setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image); + gl::Error subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image); bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat); - bool fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, - GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget); + gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea, + GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget); GLint creationLevels(GLsizei width, GLsizei height, GLsizei depth) const; int mipLevels() const; + virtual void initMipmapsImages() = 0; + bool isBaseImageZeroSize() const; + virtual bool isImageComplete(const gl::ImageIndex &index) const = 0; - Renderer *mRenderer; + bool canCreateRenderTargetForImage(const gl::ImageIndex &index) const; + virtual gl::Error ensureRenderTarget(); + + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const = 0; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0; + gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box ®ion); + + RendererD3D *mRenderer; GLenum mUsage; bool mDirtyImages; bool mImmutable; + TextureStorage *mTexStorage; private: DISALLOW_COPY_AND_ASSIGN(TextureD3D); - virtual void initializeStorage(bool renderTarget) = 0; + virtual gl::Error initializeStorage(bool renderTarget) = 0; - virtual void updateStorage() = 0; - virtual TextureStorage *getBaseLevelStorage() = 0; - virtual const ImageD3D *getBaseLevelImage() const = 0; + virtual gl::Error updateStorage() = 0; + + bool shouldUseSetData(const Image *image) const; }; class TextureD3D_2D : public TextureD3D { public: - TextureD3D_2D(Renderer *renderer); + TextureD3D_2D(RendererD3D *renderer); virtual ~TextureD3D_2D(); virtual Image *getImage(int level, int layer) const; @@ -99,50 +122,49 @@ class TextureD3D_2D : public TextureD3D GLenum getActualFormat(GLint level) const; bool isDepth(GLint level) const; - virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); - virtual void generateMipmaps(); - - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D); - virtual void initializeStorage(bool renderTarget); - TextureStorage *createCompleteStorage(bool renderTarget) const; - void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - virtual void updateStorage(); - bool ensureRenderTarget(); - virtual TextureStorage *getBaseLevelStorage(); - virtual const ImageD3D *getBaseLevelImage() const; + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; + virtual bool isImageComplete(const gl::ImageIndex &index) const; - void updateStorageLevel(int level); + gl::Error updateStorageLevel(int level); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height); - void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - TextureStorage *mTexStorage; ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureD3D_Cube : public TextureD3D { public: - TextureD3D_Cube(Renderer *renderer); + TextureD3D_Cube(RendererD3D *renderer); virtual ~TextureD3D_Cube(); virtual Image *getImage(int level, int layer) const; @@ -156,51 +178,49 @@ class TextureD3D_Cube : public TextureD3D GLenum getInternalFormat(GLint level, GLint layer) const; bool isDepth(GLint level, GLint layer) const; - virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); - virtual void generateMipmaps(); - - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube); - virtual void initializeStorage(bool renderTarget); - TextureStorage *createCompleteStorage(bool renderTarget) const; - void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - virtual void updateStorage(); - bool ensureRenderTarget(); - virtual TextureStorage *getBaseLevelStorage(); - virtual const ImageD3D *getBaseLevelImage() const; + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); bool isValidFaceLevel(int faceIndex, int level) const; bool isFaceLevelComplete(int faceIndex, int level) const; bool isCubeComplete() const; - void updateStorageFaceLevel(int faceIndex, int level); + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageFaceLevel(int faceIndex, int level); void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height); - void commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - TextureStorage *mTexStorage; }; class TextureD3D_3D : public TextureD3D { public: - TextureD3D_3D(Renderer *renderer); + TextureD3D_3D(RendererD3D *renderer); virtual ~TextureD3D_3D(); virtual Image *getImage(int level, int layer) const; @@ -213,50 +233,48 @@ class TextureD3D_3D : public TextureD3D GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; - virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); - virtual void generateMipmaps(); - - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D); - virtual void initializeStorage(bool renderTarget); - TextureStorage *createCompleteStorage(bool renderTarget) const; - void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - virtual void updateStorage(); - bool ensureRenderTarget(); - virtual TextureStorage *getBaseLevelStorage(); - virtual const ImageD3D *getBaseLevelImage() const; + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - void updateStorageLevel(int level); + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - TextureStorage *mTexStorage; }; class TextureD3D_2DArray : public TextureD3D { public: - TextureD3D_2DArray(Renderer *renderer); + TextureD3D_2DArray(RendererD3D *renderer); virtual ~TextureD3D_2DArray(); virtual Image *getImage(int level, int layer) const; @@ -265,45 +283,44 @@ class TextureD3D_2DArray : public TextureD3D GLsizei getWidth(GLint level) const; GLsizei getHeight(GLint level) const; - GLsizei getLayers(GLint level) const; GLenum getInternalFormat(GLint level) const; bool isDepth(GLint level) const; - virtual void setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels); - virtual void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); - virtual void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels); - virtual void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); - virtual void storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); + virtual gl::Error setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels); + virtual gl::Error copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); virtual void bindTexImage(egl::Surface *surface); virtual void releaseTexImage(); - virtual void generateMipmaps(); - - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); virtual unsigned int getRenderTargetSerial(const gl::ImageIndex &index); + virtual gl::ImageIndexIterator imageIterator() const; + virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const; + virtual bool isValidIndex(const gl::ImageIndex &index) const; + private: DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray); - virtual void initializeStorage(bool renderTarget); - TextureStorage *createCompleteStorage(bool renderTarget) const; - void setCompleteTexStorage(TextureStorage *newCompleteTexStorage); + virtual gl::Error initializeStorage(bool renderTarget); + virtual gl::Error createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const; + virtual gl::Error setCompleteTexStorage(TextureStorage *newCompleteTexStorage); - virtual void updateStorage(); - bool ensureRenderTarget(); - virtual TextureStorage *getBaseLevelStorage(); - virtual const ImageD3D *getBaseLevelImage() const; + virtual gl::Error updateStorage(); + virtual void initMipmapsImages(); bool isValidLevel(int level) const; bool isLevelComplete(int level) const; - void updateStorageLevel(int level); + virtual bool isImageComplete(const gl::ImageIndex &index) const; + gl::Error updateStorageLevel(int level); void deleteImages(); void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); - void commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height); // Storing images as an array of single depth textures since D3D11 treats each array level of a // Texture2D object as a separate subresource. Each layer would have to be looped over @@ -311,8 +328,6 @@ class TextureD3D_2DArray : public TextureD3D // sense for the Image class to not have to worry about layer subresource as well as mip subresources. GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - - TextureStorage *mTexStorage; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp index dedd266c09..320b74b8ed 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.cpp @@ -8,6 +8,7 @@ #include "libGLESv2/renderer/d3d/TextureStorage.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" +#include "libGLESv2/renderer/RenderTarget.h" #include "libGLESv2/renderer/Renderer.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/Texture.h" @@ -18,17 +19,14 @@ namespace rx { -unsigned int TextureStorage::mCurrentTextureSerial = 1; - TextureStorage::TextureStorage() - : mTextureSerial(issueTextureSerial()), - mFirstRenderTargetSerial(0), + : mFirstRenderTargetSerial(0), mRenderTargetSerialsLayerStride(0) {} void TextureStorage::initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride) { - mFirstRenderTargetSerial = gl::RenderbufferStorage::issueSerials(rtSerialsToReserve); + mFirstRenderTargetSerial = RenderTarget::issueSerials(rtSerialsToReserve); mRenderTargetSerialsLayerStride = rtSerialsLayerStride; } @@ -38,14 +36,4 @@ unsigned int TextureStorage::getRenderTargetSerial(const gl::ImageIndex &index) return mFirstRenderTargetSerial + static_cast(index.mipIndex) + layerOffset; } -unsigned int TextureStorage::getTextureSerial() const -{ - return mTextureSerial; -} - -unsigned int TextureStorage::issueTextureSerial() -{ - return mCurrentTextureSerial++; -} - } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h index 9cc2c2977b..da92be3c74 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureStorage.h @@ -9,20 +9,26 @@ #ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ #define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_ +#include "libGLESv2/Error.h" + #include "common/debug.h" +#include "libGLESv2/Error.h" #include +#include namespace gl { struct ImageIndex; +struct Box; +struct PixelUnpackState; } namespace rx { -class Renderer; class SwapChain; class RenderTarget; +class Image; class TextureStorage { @@ -35,8 +41,12 @@ class TextureStorage virtual bool isManaged() const = 0; virtual int getLevelCount() const = 0; - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; - virtual void generateMipmaps() = 0; + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0; + virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0; unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const; unsigned int getTextureSerial() const; @@ -47,11 +57,6 @@ class TextureStorage private: DISALLOW_COPY_AND_ASSIGN(TextureStorage); - const unsigned int mTextureSerial; - static unsigned int issueTextureSerial(); - - static unsigned int mCurrentTextureSerial; - unsigned int mFirstRenderTargetSerial; unsigned int mRenderTargetSerialsLayerStride; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp index 4f85eb94fa..73f0c79e19 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.cpp @@ -9,7 +9,7 @@ #include "libGLESv2/renderer/d3d/VertexBuffer.h" #include "libGLESv2/renderer/d3d/BufferD3D.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/VertexAttribute.h" #include "common/mathutil.h" @@ -38,7 +38,7 @@ unsigned int VertexBuffer::getSerial() const return mSerial; } -VertexBufferInterface::VertexBufferInterface(rx::Renderer *renderer, bool dynamic) : mRenderer(renderer) +VertexBufferInterface::VertexBufferInterface(RendererD3D *renderer, bool dynamic) : mRenderer(renderer) { mDynamic = dynamic; mWritePosition = 0; @@ -127,7 +127,7 @@ gl::Error VertexBufferInterface::storeVertexAttributes(const gl::VertexAttribute mWritePosition += spaceRequired; // Align to 16-byte boundary - mWritePosition = rx::roundUp(mWritePosition, 16u); + mWritePosition = roundUp(mWritePosition, 16u); return gl::Error(GL_NO_ERROR); } @@ -153,7 +153,7 @@ gl::Error VertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &a mReservedSpace += requiredSpace; // Align to 16-byte boundary - mReservedSpace = rx::roundUp(mReservedSpace, 16u); + mReservedSpace = roundUp(mReservedSpace, 16u); return gl::Error(GL_NO_ERROR); } @@ -197,7 +197,7 @@ bool VertexBufferInterface::directStoragePossible(const gl::VertexAttribute &att return !requiresConversion && isAligned; } -StreamingVertexBufferInterface::StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) +StreamingVertexBufferInterface::StreamingVertexBufferInterface(RendererD3D *renderer, std::size_t initialSize) : VertexBufferInterface(renderer, true) { setBufferSize(initialSize); } @@ -231,7 +231,7 @@ gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size) return gl::Error(GL_NO_ERROR); } -StaticVertexBufferInterface::StaticVertexBufferInterface(rx::Renderer *renderer) : VertexBufferInterface(renderer, false) +StaticVertexBufferInterface::StaticVertexBufferInterface(RendererD3D *renderer) : VertexBufferInterface(renderer, false) { } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h index fa747d9cb4..4b40818f8e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexBuffer.h @@ -26,7 +26,7 @@ struct VertexAttribCurrentValueData; namespace rx { -class Renderer; +class RendererD3D; class VertexBuffer { @@ -60,7 +60,7 @@ class VertexBuffer class VertexBufferInterface { public: - VertexBufferInterface(rx::Renderer *renderer, bool dynamic); + VertexBufferInterface(RendererD3D *renderer, bool dynamic); virtual ~VertexBufferInterface(); gl::Error reserveVertexSpace(const gl::VertexAttribute &attribute, GLsizei count, GLsizei instances); @@ -90,7 +90,7 @@ class VertexBufferInterface private: DISALLOW_COPY_AND_ASSIGN(VertexBufferInterface); - rx::Renderer *const mRenderer; + RendererD3D *const mRenderer; VertexBuffer* mVertexBuffer; @@ -102,7 +102,7 @@ class VertexBufferInterface class StreamingVertexBufferInterface : public VertexBufferInterface { public: - StreamingVertexBufferInterface(rx::Renderer *renderer, std::size_t initialSize); + StreamingVertexBufferInterface(RendererD3D *renderer, std::size_t initialSize); ~StreamingVertexBufferInterface(); protected: @@ -112,7 +112,7 @@ class StreamingVertexBufferInterface : public VertexBufferInterface class StaticVertexBufferInterface : public VertexBufferInterface { public: - explicit StaticVertexBufferInterface(rx::Renderer *renderer); + explicit StaticVertexBufferInterface(RendererD3D *renderer); ~StaticVertexBufferInterface(); gl::Error storeVertexAttributes(const gl::VertexAttribute &attrib, const gl::VertexAttribCurrentValueData ¤tValue, diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp index 7034b78eab..8d3df31c8b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp @@ -14,6 +14,7 @@ #include "libGLESv2/Buffer.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/VertexAttribute.h" +#include "libGLESv2/State.h" namespace { @@ -51,7 +52,7 @@ static int StreamingBufferElementCount(const gl::VertexAttribute &attrib, int ve return vertexDrawCount; } -VertexDataManager::VertexDataManager(Renderer *renderer) : mRenderer(renderer) +VertexDataManager::VertexDataManager(RendererD3D *renderer) : mRenderer(renderer) { for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { @@ -82,8 +83,8 @@ VertexDataManager::~VertexDataManager() } } -gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], - gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances) +gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *translated, GLsizei instances) { if (!mStreamingBuffer) { @@ -93,20 +94,22 @@ gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs // Invalidate static buffers that don't contain matching attributes for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++) { - translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1); + translated[attributeIndex].active = (state.getCurrentProgramBinary()->getSemanticIndex(attributeIndex) != -1); + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(attributeIndex); - if (translated[attributeIndex].active && attribs[attributeIndex].enabled) + if (translated[attributeIndex].active && curAttrib.enabled) { - invalidateMatchingStaticData(attribs[attributeIndex], currentValues[attributeIndex]); + invalidateMatchingStaticData(curAttrib, state.getVertexAttribCurrentValue(attributeIndex)); } } // Reserve the required space in the buffers for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].enabled) + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); + if (translated[i].active && curAttrib.enabled) { - gl::Error error = reserveSpaceForAttrib(attribs[i], currentValues[i], count, instances); + gl::Error error = reserveSpaceForAttrib(curAttrib, state.getVertexAttribCurrentValue(i), count, instances); if (error.isError()) { return error; @@ -117,12 +120,14 @@ gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs // Perform the vertex data translations for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); if (translated[i].active) { - if (attribs[i].enabled) + if (curAttrib.enabled) { - gl::Error error = storeAttribute(attribs[i], currentValues[i], &translated[i], - start, count, instances); + gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i), + &translated[i], start, count, instances); + if (error.isError()) { return error; @@ -135,7 +140,7 @@ gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE); } - gl::Error error = storeCurrentValue(attribs[i], currentValues[i], &translated[i], + gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i], &mCurrentValue[i], &mCurrentValueOffsets[i], mCurrentValueBuffer[i]); if (error.isError()) @@ -148,14 +153,15 @@ gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { - if (translated[i].active && attribs[i].enabled) + const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i); + if (translated[i].active && curAttrib.enabled) { - gl::Buffer *buffer = attribs[i].buffer.get(); + gl::Buffer *buffer = curAttrib.buffer.get(); if (buffer) { BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation()); - bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(attribs[i])); + bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib)); } } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h index 7728722246..64ef653221 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h @@ -16,8 +16,9 @@ namespace gl { -struct VertexAttribute; class ProgramBinary; +class State; +struct VertexAttribute; struct VertexAttribCurrentValueData; } @@ -26,7 +27,7 @@ namespace rx class BufferD3D; class StreamingVertexBufferInterface; class VertexBuffer; -class Renderer; +class RendererD3D; struct TranslatedAttribute { @@ -49,11 +50,11 @@ struct TranslatedAttribute class VertexDataManager { public: - VertexDataManager(rx::Renderer *renderer); + VertexDataManager(RendererD3D *renderer); virtual ~VertexDataManager(); - gl::Error prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[], - gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances); + gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count, + TranslatedAttribute *outAttribs, GLsizei instances); private: DISALLOW_COPY_AND_ASSIGN(VertexDataManager); @@ -80,7 +81,7 @@ class VertexDataManager size_t *cachedOffset, StreamingVertexBufferInterface *buffer); - rx::Renderer *const mRenderer; + RendererD3D *const mRenderer; StreamingVertexBufferInterface *mStreamingBuffer; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp index d43e65ea78..06aea9befe 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp @@ -172,7 +172,7 @@ static void Write3DVertices(const gl::Box &sourceArea, const gl::Extents &source *outTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; } -Blit11::Blit11(rx::Renderer11 *renderer) +Blit11::Blit11(Renderer11 *renderer) : mRenderer(renderer), mBlitShaderMap(compareBlitParameters), mSwizzleShaderMap(compareSwizzleParameters), mVertexBuffer(NULL), mPointSampler(NULL), mLinearSampler(NULL), mScissorEnabledRasterizerState(NULL), mScissorDisabledRasterizerState(NULL), mDepthStencilState(NULL), @@ -209,7 +209,7 @@ Blit11::Blit11(rx::Renderer11 *renderer) pointSamplerDesc.BorderColor[2] = 0.0f; pointSamplerDesc.BorderColor[3] = 0.0f; pointSamplerDesc.MinLOD = 0.0f; - pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); ASSERT(SUCCEEDED(result)); @@ -228,7 +228,7 @@ Blit11::Blit11(rx::Renderer11 *renderer) linearSamplerDesc.BorderColor[2] = 0.0f; linearSamplerDesc.BorderColor[3] = 0.0f; linearSamplerDesc.MinLOD = 0.0f; - linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; + linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); ASSERT(SUCCEEDED(result)); @@ -468,8 +468,7 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); // Unset the currently bound shader resource to avoid conflicts - ID3D11ShaderResourceView *const nullSRV = NULL; - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); // Apply render target mRenderer->setOneTimeRenderTarget(dest); @@ -485,7 +484,7 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT deviceContext->RSSetViewports(1, &viewport); // Apply textures - deviceContext->PSSetShaderResources(0, 1, &source); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); // Apply samplers deviceContext->PSSetSamplers(0, 1, &mPointSampler); @@ -494,7 +493,7 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT deviceContext->Draw(drawCount, 0); // Unbind textures and render targets and vertex buffer - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); mRenderer->unapplyRenderTargets(); @@ -507,9 +506,9 @@ gl::Error Blit11::swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderT return gl::Error(GL_NO_ERROR); } -bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) +gl::Error Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter) { HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -531,7 +530,7 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source if (i == mBlitShaderMap.end()) { UNREACHABLE(); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Could not find appropriate shader for internal texture blit."); } const Shader& shader = i->second; @@ -541,8 +540,7 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); } UINT stride = 0; @@ -587,8 +585,7 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source deviceContext->GSSetShader(shader.mGeometryShader, NULL, 0); // Unset the currently bound shader resource to avoid conflicts - ID3D11ShaderResourceView *const nullSRV = NULL; - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); // Apply render target mRenderer->setOneTimeRenderTarget(dest); @@ -604,7 +601,7 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source deviceContext->RSSetViewports(1, &viewport); // Apply textures - deviceContext->PSSetShaderResources(0, 1, &source); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); // Apply samplers ID3D11SamplerState *sampler = NULL; @@ -612,7 +609,10 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source { case GL_NEAREST: sampler = mPointSampler; break; case GL_LINEAR: sampler = mLinearSampler; break; - default: UNREACHABLE(); return false; + + default: + UNREACHABLE(); + return gl::Error(GL_OUT_OF_MEMORY, "Internal error, unknown blit filter mode."); } deviceContext->PSSetSamplers(0, 1, &sampler); @@ -620,7 +620,7 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source deviceContext->Draw(drawCount, 0); // Unbind textures and render targets and vertex buffer - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); mRenderer->unapplyRenderTargets(); @@ -630,21 +630,21 @@ bool Blit11::copyTexture(ID3D11ShaderResourceView *source, const gl::Box &source mRenderer->markAllStateDirty(); - return true; + return gl::Error(GL_NO_ERROR); } -bool Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) +gl::Error Blit11::copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) { return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource, destArea, destSize, scissor, true); } -bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) +gl::Error Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) { HRESULT result; ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -654,8 +654,7 @@ bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceAr result = deviceContext->Map(mVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if (FAILED(result)) { - ERR("Failed to map vertex buffer for texture copy, HRESULT: 0x%X.", result); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal vertex buffer for texture copy, HRESULT: 0x%X.", result); } UINT stride = 0; @@ -700,8 +699,7 @@ bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceAr deviceContext->GSSetShader(NULL, NULL, 0); // Unset the currently bound shader resource to avoid conflicts - ID3D11ShaderResourceView *const nullSRV = NULL; - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); // Apply render target deviceContext->OMSetRenderTargets(0, NULL, dest); @@ -717,7 +715,7 @@ bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceAr deviceContext->RSSetViewports(1, &viewport); // Apply textures - deviceContext->PSSetShaderResources(0, 1, &source); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, source); // Apply samplers deviceContext->PSSetSamplers(0, 1, &mPointSampler); @@ -726,7 +724,7 @@ bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceAr deviceContext->Draw(drawCount, 0); // Unbind textures and render targets and vertex buffer - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); mRenderer->unapplyRenderTargets(); @@ -736,21 +734,21 @@ bool Blit11::copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceAr mRenderer->markAllStateDirty(); - return true; + return gl::Error(GL_NO_ERROR); } -bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor) +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor) { return copyDepthStencil(source, sourceSubresource, sourceArea, sourceSize, dest, destSubresource, destArea, destSize, scissor, false); } -bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, bool stencilOnly) +gl::Error Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly) { ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); @@ -764,7 +762,7 @@ bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubreso { SafeRelease(sourceStaging); SafeRelease(destStaging); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal staging textures for depth stencil blit."); } DXGI_FORMAT format = GetTextureFormat(source); @@ -785,23 +783,23 @@ bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubreso dxgiFormatInfo.depthBits % 8 == 0); } - D3D11_MAPPED_SUBRESOURCE sourceMapping, destMapping; - deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); - deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); - - if (!sourceMapping.pData || !destMapping.pData) + D3D11_MAPPED_SUBRESOURCE sourceMapping; + HRESULT result = deviceContext->Map(sourceStaging, 0, D3D11_MAP_READ, 0, &sourceMapping); + if (FAILED(result)) { - if (!sourceMapping.pData) - { - deviceContext->Unmap(sourceStaging, 0); - } - if (!destMapping.pData) - { - deviceContext->Unmap(destStaging, 0); - } SafeRelease(sourceStaging); SafeRelease(destStaging); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal source staging texture for depth stencil blit, HRESULT: 0x%X.", result); + } + + D3D11_MAPPED_SUBRESOURCE destMapping; + result = deviceContext->Map(destStaging, 0, D3D11_MAP_WRITE, 0, &destMapping); + if (FAILED(result)) + { + deviceContext->Unmap(sourceStaging, 0); + SafeRelease(sourceStaging); + SafeRelease(destStaging); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal destination staging texture for depth stencil blit, HRESULT: 0x%X.", result); } gl::Rectangle clippedDestArea(destArea.x, destArea.y, destArea.width, destArea.height); @@ -880,7 +878,7 @@ bool Blit11::copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubreso SafeRelease(sourceStaging); SafeRelease(destStaging); - return true; + return gl::Error(GL_NO_ERROR); } bool Blit11::compareBlitParameters(const Blit11::BlitParameters &a, const Blit11::BlitParameters &b) @@ -1001,12 +999,12 @@ void Blit11::buildShaderMap() add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); - add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); - add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); + add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); + add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h index d6a0b795f4..821fa9d0cc 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.h @@ -19,12 +19,6 @@ namespace rx { class Renderer11; -enum Filter -{ - Point, - Linear, -}; - class Blit11 { public: @@ -34,24 +28,24 @@ class Blit11 gl::Error swizzleTexture(ID3D11ShaderResourceView *source, ID3D11RenderTargetView *dest, const gl::Extents &size, GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); - bool copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); + gl::Error copyTexture(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11RenderTargetView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, GLenum destFormat, GLenum filter); - bool copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor); - - bool copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor); - - bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + gl::Error copyStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, const gl::Rectangle *scissor); + gl::Error copyDepth(ID3D11ShaderResourceView *source, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11DepthStencilView *dest, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor); + private: - rx::Renderer11 *mRenderer; + Renderer11 *mRenderer; struct BlitParameters { @@ -60,9 +54,9 @@ class Blit11 bool m3DBlit; }; - bool copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, - ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, - const gl::Rectangle *scissor, bool stencilOnly); + gl::Error copyDepthStencil(ID3D11Resource *source, unsigned int sourceSubresource, const gl::Box &sourceArea, const gl::Extents &sourceSize, + ID3D11Resource *dest, unsigned int destSubresource, const gl::Box &destArea, const gl::Extents &destSize, + const gl::Rectangle *scissor, bool stencilOnly); static bool compareBlitParameters(const BlitParameters &a, const BlitParameters &b); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp index ecd4d4672b..5aab37938f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp @@ -86,7 +86,7 @@ class Buffer11::BufferStorage11 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, size_t size, size_t destOffset) = 0; - virtual bool resize(size_t size, bool preserveData) = 0; + virtual gl::Error resize(size_t size, bool preserveData) = 0; virtual void *map(size_t offset, size_t length, GLbitfield access) = 0; virtual void unmap() = 0; @@ -112,17 +112,17 @@ class Buffer11::NativeBuffer11 : public Buffer11::BufferStorage11 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, size_t size, size_t destOffset); - virtual bool resize(size_t size, bool preserveData); + virtual gl::Error resize(size_t size, bool preserveData); virtual void *map(size_t offset, size_t length, GLbitfield access); virtual void unmap(); - bool setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset); + gl::Error setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset); private: ID3D11Buffer *mNativeBuffer; - static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, BufferUsage usage, unsigned int bufferSize); + static void fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize); }; // Pack storage represents internal storage for pack buffers. We implement pack buffers @@ -135,7 +135,7 @@ class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 virtual bool copyFromStorage(BufferStorage11 *source, size_t sourceOffset, size_t size, size_t destOffset); - virtual bool resize(size_t size, bool preserveData); + virtual gl::Error resize(size_t size, bool preserveData); virtual void *map(size_t offset, size_t length, GLbitfield access); virtual void unmap(); @@ -144,7 +144,7 @@ class Buffer11::PackStorage11 : public Buffer11::BufferStorage11 private: - void flushQueuedPackCommand(); + gl::Error flushQueuedPackCommand(); ID3D11Texture2D *mStagingTexture; DXGI_FORMAT mTextureFormat; @@ -195,14 +195,14 @@ gl::Error Buffer11::setData(const void *data, size_t size, GLenum usage) return error; } -void *Buffer11::getData() +gl::Error Buffer11::getData(const uint8_t **outData) { NativeBuffer11 *stagingBuffer = getStagingBuffer(); if (!stagingBuffer) { // Out-of-memory - return NULL; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get internal staging buffer."); } if (stagingBuffer->getDataRevision() > mResolvedDataRevision) @@ -211,7 +211,7 @@ void *Buffer11::getData() { if (!mResolvedData.resize(stagingBuffer->getSize())) { - return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize data resolve buffer."); } } @@ -221,7 +221,7 @@ void *Buffer11::getData() HRESULT result = context->Map(stagingBuffer->getNativeBuffer(), 0, D3D11_MAP_READ, 0, &mappedResource); if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer, result: 0x%X.", result); } memcpy(mResolvedData.data(), mappedResource.pData, stagingBuffer->getSize()); @@ -238,13 +238,14 @@ void *Buffer11::getData() { if (!mResolvedData.resize(mSize)) { - return gl::error(GL_OUT_OF_MEMORY, (void*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize data resolve buffer."); } } ASSERT(mResolvedData.size() >= mSize); - return mResolvedData.data(); + *outData = mResolvedData.data(); + return gl::Error(GL_NO_ERROR); } gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) @@ -265,15 +266,17 @@ gl::Error Buffer11::setSubData(const void *data, size_t size, size_t offset) if (stagingBuffer->getSize() < requiredSize) { bool preserveData = (offset > 0); - if (!stagingBuffer->resize(requiredSize, preserveData)) + gl::Error error = stagingBuffer->resize(requiredSize, preserveData); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal staging buffer."); + return error; } } - if (!stagingBuffer->setData(D3D11_MAP_WRITE, reinterpret_cast(data), size, offset)) + gl::Error error = stagingBuffer->setData(D3D11_MAP_WRITE, reinterpret_cast(data), size, offset); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Failed to set data on internal staging buffer."); + return error; } stagingBuffer->setDataRevision(stagingBuffer->getDataRevision() + 1); @@ -411,7 +414,7 @@ void Buffer11::markBufferUsage() } } -Renderer* Buffer11::getRenderer() +RendererD3D* Buffer11::getRenderer() { return mRenderer; } @@ -527,7 +530,7 @@ Buffer11::BufferStorage11 *Buffer11::getBufferStorage(BufferUsage usage) // resize buffer if (directBuffer->getSize() < mSize) { - if (!directBuffer->resize(mSize, true)) + if (directBuffer->resize(mSize, true).isError()) { // Out of memory error return NULL; @@ -667,6 +670,9 @@ bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t s // Offset bounds are validated at the API layer ASSERT(sourceOffset + size <= destOffset + mBufferSize); memcpy(destPointer, sourcePointer, size); + + context->Unmap(mNativeBuffer, 0); + source->unmap(); } else { @@ -689,7 +695,7 @@ bool Buffer11::NativeBuffer11::copyFromStorage(BufferStorage11 *source, size_t s return createBuffer; } -bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) +gl::Error Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) { ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); @@ -702,7 +708,7 @@ bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer, result: 0x%X.", result); } if (mNativeBuffer && preserveData) @@ -727,10 +733,10 @@ bool Buffer11::NativeBuffer11::resize(size_t size, bool preserveData) mBufferSize = bufferDesc.ByteWidth; - return true; + return gl::Error(GL_NO_ERROR); } -void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer *renderer, +void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Renderer11 *renderer, BufferUsage usage, unsigned int bufferSize) { bufferDesc->ByteWidth = bufferSize; @@ -748,7 +754,7 @@ void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Ren case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: bufferDesc->Usage = D3D11_USAGE_DEFAULT; bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; - if (!static_cast(renderer)->isLevel9()) + if (!renderer->isLevel9()) bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; bufferDesc->CPUAccessFlags = 0; break; @@ -797,7 +803,7 @@ void *Buffer11::NativeBuffer11::map(size_t offset, size_t length, GLbitfield acc return static_cast(mappedResource.pData) + offset; } -bool Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset) +gl::Error Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, size_t size, size_t offset) { ID3D11DeviceContext *context = mRenderer->getDeviceContext(); @@ -805,7 +811,7 @@ bool Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, s HRESULT result = context->Map(mNativeBuffer, 0, mapMode, 0, &mappedResource); if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal buffer, result: 0x%X.", result); } uint8_t *offsetBufferPointer = reinterpret_cast(mappedResource.pData) + offset; @@ -813,7 +819,7 @@ bool Buffer11::NativeBuffer11::setData(D3D11_MAP mapMode, const uint8_t *data, s context->Unmap(mNativeBuffer, 0); - return true; + return gl::Error(GL_NO_ERROR); } void Buffer11::NativeBuffer11::unmap() @@ -847,18 +853,18 @@ bool Buffer11::PackStorage11::copyFromStorage(BufferStorage11 *source, size_t so return false; } -bool Buffer11::PackStorage11::resize(size_t size, bool preserveData) +gl::Error Buffer11::PackStorage11::resize(size_t size, bool preserveData) { if (size != mBufferSize) { if (!mMemoryBuffer.resize(size)) { - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to resize internal buffer storage."); } mBufferSize = size; } - return true; + return gl::Error(GL_NO_ERROR); } void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield access) @@ -869,7 +875,12 @@ void *Buffer11::PackStorage11::map(size_t offset, size_t length, GLbitfield acce // and if D3D packs the staging texture memory identically to how we would fill // the pack buffer according to the current pack state. - flushQueuedPackCommand(); + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return NULL; + } + mDataModified = (mDataModified || (access & GL_MAP_WRITE_BIT) != 0); return mMemoryBuffer.data() + offset; @@ -882,7 +893,12 @@ void Buffer11::PackStorage11::unmap() gl::Error Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT srcSubresource, const PackPixelsParams ¶ms) { - flushQueuedPackCommand(); + gl::Error error = flushQueuedPackCommand(); + if (error.isError()) + { + return error; + } + mQueuedPackCommand = new PackPixelsParams(params); D3D11_TEXTURE2D_DESC textureDesc; @@ -947,15 +963,21 @@ gl::Error Buffer11::PackStorage11::packPixels(ID3D11Texture2D *srcTexure, UINT s return gl::Error(GL_NO_ERROR); } -void Buffer11::PackStorage11::flushQueuedPackCommand() +gl::Error Buffer11::PackStorage11::flushQueuedPackCommand() { ASSERT(mMemoryBuffer.size() > 0); if (mQueuedPackCommand) { - mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); + gl::Error error = mRenderer->packPixels(mStagingTexture, *mQueuedPackCommand, mMemoryBuffer.data()); SafeDelete(mQueuedPackCommand); + if (error.isError()) + { + return error; + } } + + return gl::Error(GL_NO_ERROR); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h index 5f24fb4e2d..1c06bbf88a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.h @@ -47,7 +47,7 @@ typedef size_t DataRevision; class Buffer11 : public BufferD3D { public: - Buffer11(rx::Renderer11 *renderer); + Buffer11(Renderer11 *renderer); virtual ~Buffer11(); static Buffer11 *makeBuffer11(BufferImpl *buffer); @@ -60,11 +60,11 @@ class Buffer11 : public BufferD3D // BufferD3D implementation virtual size_t getSize() const { return mSize; } virtual bool supportsDirectBinding() const; - virtual Renderer* getRenderer(); + RendererD3D *getRenderer() override; // BufferImpl implementation virtual gl::Error setData(const void* data, size_t size, GLenum usage); - virtual void *getData(); + gl::Error getData(const uint8_t **outData) override; virtual gl::Error setSubData(const void* data, size_t size, size_t offset); virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); @@ -78,7 +78,7 @@ class Buffer11 : public BufferD3D class NativeBuffer11; class PackStorage11; - rx::Renderer11 *mRenderer; + Renderer11 *mRenderer; size_t mSize; BufferStorage11 *mMappedStorage; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp index 765d34fd3f..7185a05506 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp @@ -104,7 +104,7 @@ Clear11::Clear11(Renderer11 *renderer) rsDesc.DepthBias = 0; rsDesc.DepthBiasClamp = 0.0f; rsDesc.SlopeScaledDepthBias = 0.0f; - rsDesc.DepthClipEnable = mRenderer->isLevel9(); + rsDesc.DepthClipEnable = renderer->isLevel9(); rsDesc.ScissorEnable = FALSE; rsDesc.MultisampleEnable = FALSE; rsDesc.AntialiasedLineEnable = FALSE; @@ -119,7 +119,6 @@ Clear11::Clear11(Renderer11 *renderer) memset(&mIntClearShader, 0, sizeof(ClearShader)); return; } - mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); } @@ -154,7 +153,7 @@ Clear11::~Clear11() SafeRelease(mRasterizerState); } -gl::Error Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +gl::Error Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) { // First determine if a scissored clear is needed, this will always require drawing a quad. // @@ -217,10 +216,11 @@ gl::Error Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl:: gl::FramebufferAttachment *attachment = frameBuffer->getColorbuffer(colorAttachment); if (attachment) { - RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(attachment); - if (!renderTarget) + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); + return error; } const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(attachment->getInternalFormat()); @@ -290,10 +290,11 @@ gl::Error Clear11::clearFramebuffer(const gl::ClearParameters &clearParams, gl:: gl::FramebufferAttachment *attachment = frameBuffer->getDepthOrStencilbuffer(); if (attachment) { - RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(attachment); - if (!renderTarget) + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); + return error; } const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(attachment->getActualFormat()); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h index be8e187c40..a7e8fea56a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.h @@ -32,7 +32,7 @@ class Clear11 ~Clear11(); // Clears the framebuffer with the supplied clear parameters, assumes that the framebuffer is currently applied. - gl::Error clearFramebuffer(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + gl::Error clearFramebuffer(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer); private: Renderer11 *mRenderer; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp index a841b52862..f44d934056 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.cpp @@ -4,67 +4,229 @@ // found in the LICENSE file. // -// Fence11.cpp: Defines the rx::Fence11 class which implements rx::FenceImpl. +// Fence11.cpp: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. #include "libGLESv2/renderer/d3d/d3d11/Fence11.h" #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/main.h" +#include "common/utilities.h" + namespace rx { -Fence11::Fence11(rx::Renderer11 *renderer) -{ - mRenderer = renderer; - mQuery = NULL; -} +// +// Template helpers for set and test operations. +// -Fence11::~Fence11() +template +gl::Error FenceSetHelper(FenceClass *fence) { - SafeRelease(mQuery); -} - -bool Fence11::isSet() const -{ - return mQuery != NULL; -} - -void Fence11::set() -{ - if (!mQuery) + if (!fence->mQuery) { D3D11_QUERY_DESC queryDesc; queryDesc.Query = D3D11_QUERY_EVENT; queryDesc.MiscFlags = 0; - if (FAILED(mRenderer->getDevice()->CreateQuery(&queryDesc, &mQuery))) + HRESULT result = fence->mRenderer->getDevice()->CreateQuery(&queryDesc, &fence->mQuery); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); } } - mRenderer->getDeviceContext()->End(mQuery); + fence->mRenderer->getDeviceContext()->End(fence->mQuery); + return gl::Error(GL_NO_ERROR); } -bool Fence11::test(bool flushCommandBuffer) +template +gl::Error FenceTestHelper(FenceClass *fence, bool flushCommandBuffer, GLboolean *outFinished) { - ASSERT(mQuery); + ASSERT(fence->mQuery); UINT getDataFlags = (flushCommandBuffer ? 0 : D3D11_ASYNC_GETDATA_DONOTFLUSH); - HRESULT result = mRenderer->getDeviceContext()->GetData(mQuery, NULL, 0, getDataFlags); + HRESULT result = fence->mRenderer->getDeviceContext()->GetData(fence->mQuery, NULL, 0, getDataFlags); - if (mRenderer->isDeviceLost()) + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, true); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); + } + else if (fence->mRenderer->isDeviceLost()) + { + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); } ASSERT(result == S_OK || result == S_FALSE); - return (result == S_OK); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); } -bool Fence11::hasError() const +// +// FenceNV11 +// + +FenceNV11::FenceNV11(Renderer11 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) { - return mRenderer->isDeviceLost(); } +FenceNV11::~FenceNV11() +{ + SafeRelease(mQuery); } + +gl::Error FenceNV11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceNV11::test(bool flushCommandBuffer, GLboolean *outFinished) +{ + return FenceTestHelper(this, flushCommandBuffer, outFinished); +} + +gl::Error FenceNV11::finishFence(GLboolean *outFinished) +{ + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + Sleep(0); + } + + return gl::Error(GL_NO_ERROR); +} + +// +// FenceSync11 +// + +// Important note on accurate timers in Windows: +// +// QueryPerformanceCounter has a few major issues, including being 10x as expensive to call +// as timeGetTime on laptops and "jumping" during certain hardware events. +// +// See the comments at the top of the Chromium source file "chromium/src/base/time/time_win.cc" +// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time_win.cc +// +// We still opt to use QPC. In the present and moving forward, most newer systems will not suffer +// from buggy implementations. + +FenceSync11::FenceSync11(Renderer11 *renderer) + : FenceSyncImpl(), + mRenderer(renderer), + mQuery(NULL) +{ + LARGE_INTEGER counterFreqency = { 0 }; + BOOL success = QueryPerformanceFrequency(&counterFreqency); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + mCounterFrequency = counterFreqency.QuadPart; +} + +FenceSync11::~FenceSync11() +{ + SafeRelease(mQuery); +} + +gl::Error FenceSync11::set() +{ + return FenceSetHelper(this); +} + +gl::Error FenceSync11::clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult) +{ + ASSERT(outResult); + + bool flushCommandBuffer = ((flags & GL_SYNC_FLUSH_COMMANDS_BIT) != 0); + + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + + if (result == GL_TRUE) + { + *outResult = GL_ALREADY_SIGNALED; + return gl::Error(GL_NO_ERROR); + } + + if (timeout == 0) + { + *outResult = GL_TIMEOUT_EXPIRED; + return gl::Error(GL_NO_ERROR); + } + + LARGE_INTEGER currentCounter = { 0 }; + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + LONGLONG timeoutInSeconds = static_cast(timeout) * static_cast(1000000ll); + LONGLONG endCounter = currentCounter.QuadPart + mCounterFrequency * timeoutInSeconds; + + while (currentCounter.QuadPart < endCounter && !result) + { + Sleep(0); + BOOL success = QueryPerformanceCounter(¤tCounter); + UNUSED_ASSERTION_VARIABLE(success); + ASSERT(success); + + error = FenceTestHelper(this, flushCommandBuffer, &result); + if (error.isError()) + { + *outResult = GL_WAIT_FAILED; + return error; + } + } + + if (currentCounter.QuadPart >= endCounter) + { + *outResult = GL_TIMEOUT_EXPIRED; + } + else + { + *outResult = GL_CONDITION_SATISFIED; + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::serverWait(GLbitfield flags, GLuint64 timeout) +{ + // Because our API is currently designed to be called from a single thread, we don't need to do + // extra work for a server-side fence. GPU commands issued after the fence is created will always + // be processed after the fence is signaled. + return gl::Error(GL_NO_ERROR); +} + +gl::Error FenceSync11::getStatus(GLint *outResult) +{ + GLboolean result = GL_FALSE; + gl::Error error = FenceTestHelper(this, false, &result); + if (error.isError()) + { + // The spec does not specify any way to report errors during the status test (e.g. device lost) + // so we report the fence is unblocked in case of error or signaled. + *outResult = GL_SIGNALED; + + return error; + } + + *outResult = (result ? GL_SIGNALED : GL_UNSIGNALED); + return gl::Error(GL_NO_ERROR); +} + +} // namespace rx diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h index 50c7621776..1223a53b90 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Fence11.h @@ -4,10 +4,10 @@ // found in the LICENSE file. // -// Fence11.h: Defines the rx::Fence11 class which implements rx::FenceImpl. +// Fence11.h: Defines the rx::FenceNV11 and rx::FenceSync11 classes which implement rx::FenceNVImpl and rx::FenceSyncImpl. -#ifndef LIBGLESV2_RENDERER_Fence11_H_ -#define LIBGLESV2_RENDERER_Fence11_H_ +#ifndef LIBGLESV2_RENDERER_FENCE11_H_ +#define LIBGLESV2_RENDERER_FENCE11_H_ #include "libGLESv2/renderer/FenceImpl.h" @@ -15,24 +15,48 @@ namespace rx { class Renderer11; -class Fence11 : public FenceImpl +class FenceNV11 : public FenceNVImpl { public: - explicit Fence11(rx::Renderer11 *renderer); - virtual ~Fence11(); + explicit FenceNV11(Renderer11 *renderer); + virtual ~FenceNV11(); - bool isSet() const; - void set(); - bool test(bool flushCommandBuffer); - bool hasError() const; + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); private: - DISALLOW_COPY_AND_ASSIGN(Fence11); + DISALLOW_COPY_AND_ASSIGN(FenceNV11); - rx::Renderer11 *mRenderer; + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; ID3D11Query *mQuery; }; +class FenceSync11 : public FenceSyncImpl +{ + public: + explicit FenceSync11(Renderer11 *renderer); + virtual ~FenceSync11(); + + gl::Error set(); + gl::Error clientWait(GLbitfield flags, GLuint64 timeout, GLenum *outResult); + gl::Error serverWait(GLbitfield flags, GLuint64 timeout); + gl::Error getStatus(GLint *outResult); + + private: + DISALLOW_COPY_AND_ASSIGN(FenceSync11); + + template friend gl::Error FenceSetHelper(T *fence); + template friend gl::Error FenceTestHelper(T *fence, bool flushCommandBuffer, GLboolean *outFinished); + + Renderer11 *mRenderer; + ID3D11Query *mQuery; + LONGLONG mCounterFrequency; +}; + } #endif // LIBGLESV2_RENDERER_FENCE11_H_ diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp index 7536713af4..e6f3e90683 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp @@ -9,6 +9,7 @@ #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" @@ -22,15 +23,16 @@ namespace rx { Image11::Image11() + : mRenderer(NULL), + mDXGIFormat(DXGI_FORMAT_UNKNOWN), + mStagingTexture(NULL), + mStagingSubresource(0), + mRecoverFromStorage(false), + mAssociatedStorage(NULL), + mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()), + mRecoveredFromStorageCount(0) + { - mStagingTexture = NULL; - mRenderer = NULL; - mDXGIFormat = DXGI_FORMAT_UNKNOWN; - mRecoverFromStorage = false; - mAssociatedStorage = NULL; - mAssociatedStorageLevel = 0; - mAssociatedStorageLayerTarget = 0; - mRecoveredFromStorageCount = 0; } Image11::~Image11() @@ -41,11 +43,11 @@ Image11::~Image11() Image11 *Image11::makeImage11(Image *img) { - ASSERT(HAS_DYNAMIC_TYPE(rx::Image11*, img)); - return static_cast(img); + ASSERT(HAS_DYNAMIC_TYPE(Image11*, img)); + return static_cast(img); } -void Image11::generateMipmap(Image11 *dest, Image11 *src) +gl::Error Image11::generateMipmap(Image11 *dest, Image11 *src) { ASSERT(src->getDXGIFormat() == dest->getDXGIFormat()); ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth()); @@ -55,21 +57,18 @@ void Image11::generateMipmap(Image11 *dest, Image11 *src) ASSERT(dxgiFormatInfo.mipGenerationFunction != NULL); D3D11_MAPPED_SUBRESOURCE destMapped; - HRESULT destMapResult = dest->map(D3D11_MAP_WRITE, &destMapped); - if (FAILED(destMapResult)) + gl::Error error = dest->map(D3D11_MAP_WRITE, &destMapped); + if (error.isError()) { - ERR("Failed to map destination image for mip map generation. HRESULT:0x%X", destMapResult); - return; + return error; } D3D11_MAPPED_SUBRESOURCE srcMapped; - HRESULT srcMapResult = src->map(D3D11_MAP_READ, &srcMapped); - if (FAILED(srcMapResult)) + error = src->map(D3D11_MAP_READ, &srcMapped); + if (error.isError()) { - ERR("Failed to map source image for mip map generation. HRESULT:0x%X", srcMapResult); - dest->unmap(); - return; + return error; } const uint8_t *sourceData = reinterpret_cast(srcMapped.pData); @@ -83,6 +82,8 @@ void Image11::generateMipmap(Image11 *dest, Image11 *src) src->unmap(); dest->markDirty(); + + return gl::Error(GL_NO_ERROR); } bool Image11::isDirty() const @@ -99,32 +100,10 @@ bool Image11::isDirty() const return mDirty; } -bool Image11::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image11::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); - return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height); -} + TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage); -bool Image11::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); - return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height); -} - -bool Image11::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) -{ - TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); - return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height); -} - -bool Image11::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height) -{ - TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); - return copyToStorageImpl(storage11, level, arrayLayer, xoffset, yoffset, width, height); -} - -bool Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times, // then we should just keep the staging texture around to prevent the copying from impacting perf. // We allow the Image11 to copy its data to/from TextureStorage once. @@ -134,23 +113,38 @@ bool Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int laye if (attemptToReleaseStagingTexture) { // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it. - storage11->releaseAssociatedImage(level, layerTarget, this); + gl::Error error = storage11->releaseAssociatedImage(index, this); + if (error.isError()) + { + return error; + } } - bool updateSubresourceSuccess = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, layerTarget, xoffset, yoffset, 0, width, height, 1); + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) + { + return error; + } + + error = storage11->updateSubresourceLevel(stagingTexture, stagingSubresourceIndex, index, region); + if (error.isError()) + { + return error; + } // Once the image data has been copied into the Storage, we can release it locally. - if (attemptToReleaseStagingTexture && updateSubresourceSuccess) + if (attemptToReleaseStagingTexture) { - storage11->associateImage(this, level, layerTarget); + storage11->associateImage(this, index); releaseStagingTexture(); mRecoverFromStorage = true; mAssociatedStorage = storage11; - mAssociatedStorageLevel = level; - mAssociatedStorageLayerTarget = layerTarget; + mAssociatedImageIndex = index; } - return updateSubresourceSuccess; + return gl::Error(GL_NO_ERROR); } bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const @@ -158,13 +152,17 @@ bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const return (mAssociatedStorage == textureStorage); } -bool Image11::recoverFromAssociatedStorage() +gl::Error Image11::recoverFromAssociatedStorage() { if (mRecoverFromStorage) { - createStagingTexture(); + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } - bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this); + bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this); // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten. @@ -173,17 +171,21 @@ bool Image11::recoverFromAssociatedStorage() if (textureStorageCorrect) { // CopySubResource from the Storage to the Staging texture - mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedStorageLevel, mAssociatedStorageLayerTarget, 0, 0, 0, mWidth, mHeight, mDepth); + gl::Box region(0, 0, 0, mWidth, mHeight, mDepth); + error = mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region); + if (error.isError()) + { + return error; + } + mRecoveredFromStorageCount += 1; } // Reset all the recovery parameters, even if the texture storage association is broken. disassociateStorage(); - - return textureStorageCorrect; } - return false; + return gl::Error(GL_NO_ERROR); } void Image11::disassociateStorage() @@ -191,16 +193,15 @@ void Image11::disassociateStorage() if (mRecoverFromStorage) { // Make the texturestorage release the Image11 too - mAssociatedStorage->disassociateImage(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this); + mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this); mRecoverFromStorage = false; mAssociatedStorage = NULL; - mAssociatedStorageLevel = 0; - mAssociatedStorageLayerTarget = 0; + mAssociatedImageIndex = gl::ImageIndex::MakeInvalid(); } } -bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) +bool Image11::redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) { if (mWidth != width || mHeight != height || @@ -227,7 +228,7 @@ bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, mActualFormat = dxgiFormatInfo.internalFormat; mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); - SafeRelease(mStagingTexture); + releaseStagingTexture(); mDirty = (formatInfo.dataInitializerFunction != NULL); return true; @@ -247,8 +248,8 @@ DXGI_FORMAT Image11::getDXGIFormat() const // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle. -void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) +gl::Error Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) { const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); GLsizei inputRowPitch = formatInfo.computeRowPitch(type, width, unpackAlignment); @@ -261,11 +262,10 @@ void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei widt LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type); D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - if (FAILED(result)) + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) { - ERR("Could not map image for loading."); - return; + return error; } uint8_t* offsetMappedData = (reinterpret_cast(mappedImage.pData) + (yoffset * mappedImage.RowPitch + xoffset * outputPixelSize + zoffset * mappedImage.DepthPitch)); @@ -274,10 +274,12 @@ void Image11::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei widt offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); + + return gl::Error(GL_NO_ERROR); } -void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) +gl::Error Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) { const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); GLsizei inputRowPitch = formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, width, 1); @@ -295,11 +297,10 @@ void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GL LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE); D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - if (FAILED(result)) + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) { - ERR("Could not map image for loading."); - return; + return error; } uint8_t* offsetMappedData = reinterpret_cast(mappedImage.pData) + ((yoffset / outputBlockHeight) * mappedImage.RowPitch + @@ -311,81 +312,130 @@ void Image11::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GL offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); + + return gl::Error(GL_NO_ERROR); } -void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) { - gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer(); + RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source); + ASSERT(sourceRenderTarget->getTexture()); - if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat) + UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex(); + ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject(sourceRenderTarget->getTexture()); + + if (!sourceTexture2D) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source RenderTarget."); + } + + gl::Error error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); + + SafeRelease(sourceTexture2D); + + return error; +} + +gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source) +{ + TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source); + + UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex); + ID3D11Resource *resource = NULL; + gl::Error error = sourceStorage11->getResource(&resource); + if (error.isError()) + { + return error; + } + + ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject(resource); + + if (!sourceTexture2D) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the ID3D11Texture2D from the source TextureStorage."); + } + + error = copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex); + + SafeRelease(sourceTexture2D); + + return error; +} + +gl::Error Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource) +{ + D3D11_TEXTURE2D_DESC textureDesc; + source->GetDesc(&textureDesc); + + if (textureDesc.Format == mDXGIFormat) { // No conversion needed-- use copyback fastpath - ID3D11Texture2D *colorBufferTexture = NULL; - unsigned int subresourceIndex = 0; - - if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + ID3D11Resource *stagingTexture = NULL; + unsigned int stagingSubresourceIndex = 0; + gl::Error error = getStagingTexture(&stagingTexture, &stagingSubresourceIndex); + if (error.isError()) { - D3D11_TEXTURE2D_DESC textureDesc; - colorBufferTexture->GetDesc(&textureDesc); + return error; + } - ID3D11Device *device = mRenderer->getDevice(); - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - ID3D11Texture2D* srcTex = NULL; - if (textureDesc.SampleDesc.Count > 1) + UINT subresourceAfterResolve = sourceSubResource; + + ID3D11Texture2D* srcTex = NULL; + if (textureDesc.SampleDesc.Count > 1) + { + D3D11_TEXTURE2D_DESC resolveDesc; + resolveDesc.Width = textureDesc.Width; + resolveDesc.Height = textureDesc.Height; + resolveDesc.MipLevels = 1; + resolveDesc.ArraySize = 1; + resolveDesc.Format = textureDesc.Format; + resolveDesc.SampleDesc.Count = 1; + resolveDesc.SampleDesc.Quality = 0; + resolveDesc.Usage = D3D11_USAGE_DEFAULT; + resolveDesc.BindFlags = 0; + resolveDesc.CPUAccessFlags = 0; + resolveDesc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); + if (FAILED(result)) { - D3D11_TEXTURE2D_DESC resolveDesc; - resolveDesc.Width = textureDesc.Width; - resolveDesc.Height = textureDesc.Height; - resolveDesc.MipLevels = 1; - resolveDesc.ArraySize = 1; - resolveDesc.Format = textureDesc.Format; - resolveDesc.SampleDesc.Count = 1; - resolveDesc.SampleDesc.Quality = 0; - resolveDesc.Usage = D3D11_USAGE_DEFAULT; - resolveDesc.BindFlags = 0; - resolveDesc.CPUAccessFlags = 0; - resolveDesc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex); - if (FAILED(result)) - { - ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); - return; - } - - deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format); - subresourceIndex = 0; - } - else - { - srcTex = colorBufferTexture; - srcTex->AddRef(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result); } - D3D11_BOX srcBox; - srcBox.left = x; - srcBox.right = x + width; - srcBox.top = y; - srcBox.bottom = y + height; - srcBox.front = 0; - srcBox.back = 1; + deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format); + subresourceAfterResolve = 0; + } + else + { + srcTex = source; + } - deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox); + D3D11_BOX srcBox; + srcBox.left = sourceArea.x; + srcBox.right = sourceArea.x + sourceArea.width; + srcBox.top = sourceArea.y; + srcBox.bottom = sourceArea.y + sourceArea.height; + srcBox.front = 0; + srcBox.back = 1; + deviceContext->CopySubresourceRegion(stagingTexture, stagingSubresourceIndex, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox); + + if (textureDesc.SampleDesc.Count > 1) + { SafeRelease(srcTex); - SafeRelease(colorBufferTexture); } } else { // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels D3D11_MAPPED_SUBRESOURCE mappedImage; - HRESULT result = map(D3D11_MAP_WRITE, &mappedImage); - if (FAILED(result)) + gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); + if (error.isError()) { - ERR("Failed to map texture for Image11::copy, HRESULT: 0x%X.", result); - return; + return error; } // determine the offset coordinate into the destination buffer @@ -394,17 +444,32 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); - mRenderer->readPixels(source, x, y, width, height, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); + error = mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset); unmap(); + + if (error.isError()) + { + return error; + } } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *Image11::getStagingTexture() +gl::Error Image11::getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex) { - createStagingTexture(); + gl::Error error = createStagingTexture(); + if (error.isError()) + { + return error; + } - return mStagingTexture; + *outStagingTexture = mStagingTexture; + *outSubresourceIndex = mStagingSubresource; + return gl::Error(GL_NO_ERROR); } void Image11::releaseStagingTexture() @@ -412,149 +477,149 @@ void Image11::releaseStagingTexture() SafeRelease(mStagingTexture); } -unsigned int Image11::getStagingSubresource() -{ - createStagingTexture(); - - return mStagingSubresource; -} - -void Image11::createStagingTexture() +gl::Error Image11::createStagingTexture() { if (mStagingTexture) { - return; + return gl::Error(GL_NO_ERROR); } + ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0); + const DXGI_FORMAT dxgiFormat = getDXGIFormat(); - if (mWidth > 0 && mHeight > 0 && mDepth > 0) + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + int lodOffset = 1; + GLsizei width = mWidth; + GLsizei height = mHeight; + + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); + + if (mTarget == GL_TEXTURE_3D) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; + ID3D11Texture3D *newTexture = NULL; - int lodOffset = 1; - GLsizei width = mWidth; - GLsizei height = mHeight; + D3D11_TEXTURE3D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.Depth = mDepth; + desc.MipLevels = lodOffset + 1; + desc.Format = dxgiFormat; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset); - - if (mTarget == GL_TEXTURE_3D) + if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) { - ID3D11Texture3D *newTexture = NULL; + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth, + lodOffset + 1, &initialData, &textureData); - D3D11_TEXTURE3D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.Depth = mDepth; - desc.MipLevels = lodOffset + 1; - desc.Format = dxgiFormat; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) - { - std::vector initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, width, height, mDepth, - lodOffset + 1, &initialData, &textureData); - - result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); - } - else - { - result = device->CreateTexture3D(&desc, NULL, &newTexture); - } - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - return gl::error(GL_OUT_OF_MEMORY); - } - - mStagingTexture = newTexture; - mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); - } - else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) - { - ID3D11Texture2D *newTexture = NULL; - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = lodOffset + 1; - desc.ArraySize = 1; - desc.Format = dxgiFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - - if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) - { - std::vector initialData; - std::vector< std::vector > textureData; - d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1, - lodOffset + 1, &initialData, &textureData); - - result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); - } - else - { - result = device->CreateTexture2D(&desc, NULL, &newTexture); - } - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - return gl::error(GL_OUT_OF_MEMORY); - } - - mStagingTexture = newTexture; - mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + result = device->CreateTexture3D(&desc, initialData.data(), &newTexture); } else { - UNREACHABLE(); + result = device->CreateTexture3D(&desc, NULL, &newTexture); } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else if (mTarget == GL_TEXTURE_2D || mTarget == GL_TEXTURE_2D_ARRAY || mTarget == GL_TEXTURE_CUBE_MAP) + { + ID3D11Texture2D *newTexture = NULL; + + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = lodOffset + 1; + desc.ArraySize = 1; + desc.Format = dxgiFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + + if (d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) + { + std::vector initialData; + std::vector< std::vector > textureData; + d3d11::GenerateInitialTextureData(mInternalFormat, width, height, 1, + lodOffset + 1, &initialData, &textureData); + + result = device->CreateTexture2D(&desc, initialData.data(), &newTexture); + } + else + { + result = device->CreateTexture2D(&desc, NULL, &newTexture); + } + + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create staging texture, result: 0x%X.", result); + } + + mStagingTexture = newTexture; + mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1); + } + else + { + UNREACHABLE(); } mDirty = false; + return gl::Error(GL_NO_ERROR); } -HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) +gl::Error Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) { - createStagingTexture(); - // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE. - recoverFromAssociatedStorage(); - - HRESULT result = E_FAIL; - - if (mStagingTexture) + gl::Error error = recoverFromAssociatedStorage(); + if (error.isError()) { - ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - result = deviceContext->Map(mStagingTexture, mStagingSubresource, mapType, 0, map); - - // this can fail if the device is removed (from TDR) - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - } - else if (SUCCEEDED(result)) - { - mDirty = true; - } + return error; } - return result; + ID3D11Resource *stagingTexture = NULL; + unsigned int subresourceIndex = 0; + error = getStagingTexture(&stagingTexture, &subresourceIndex); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); + + ASSERT(mStagingTexture); + HRESULT result = deviceContext->Map(stagingTexture, subresourceIndex, mapType, 0, map); + + // this can fail if the device is removed (from TDR) + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map staging texture, result: 0x%X.", result); + } + + mDirty = true; + + return gl::Error(GL_NO_ERROR); } void Image11::unmap() diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h index a76a61f036..a936e6d7b2 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h @@ -11,6 +11,7 @@ #define LIBGLESV2_RENDERER_IMAGE11_H_ #include "libGLESv2/renderer/d3d/ImageD3D.h" +#include "libGLESv2/ImageIndex.h" #include "common/debug.h" @@ -21,7 +22,6 @@ class Framebuffer; namespace rx { -class Renderer; class Renderer11; class TextureStorage11; @@ -33,42 +33,41 @@ class Image11 : public ImageD3D static Image11 *makeImage11(Image *img); - static void generateMipmap(Image11 *dest, Image11 *src); + static gl::Error generateMipmap(Image11 *dest, Image11 *src); virtual bool isDirty() const; - virtual bool copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); - virtual bool copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height); + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); - virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); + bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) override; DXGI_FORMAT getDXGIFormat() const; - - virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input); - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input); - bool recoverFromAssociatedStorage(); + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); + + gl::Error recoverFromAssociatedStorage(); bool isAssociatedStorageValid(TextureStorage11* textureStorage) const; void disassociateStorage(); protected: - HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); + gl::Error map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); void unmap(); private: DISALLOW_COPY_AND_ASSIGN(Image11); - bool copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box ®ion); + gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource); - ID3D11Resource *getStagingTexture(); - unsigned int getStagingSubresource(); - void createStagingTexture(); + gl::Error getStagingTexture(ID3D11Resource **outStagingTexture, unsigned int *outSubresourceIndex); + gl::Error createStagingTexture(); void releaseStagingTexture(); Renderer11 *mRenderer; @@ -79,8 +78,7 @@ class Image11 : public ImageD3D bool mRecoverFromStorage; TextureStorage11 *mAssociatedStorage; - int mAssociatedStorageLevel; - int mAssociatedStorageLayerTarget; + gl::ImageIndex mAssociatedImageIndex; unsigned int mRecoveredFromStorageCount; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h index f7c2b38e7e..3351df5ec1 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/IndexBuffer11.h @@ -40,7 +40,7 @@ class IndexBuffer11 : public IndexBuffer private: DISALLOW_COPY_AND_ASSIGN(IndexBuffer11); - rx::Renderer11 *const mRenderer; + Renderer11 *const mRenderer; ID3D11Buffer *mBuffer; unsigned int mBufferSize; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp index d835e4fa68..ff90a6a69a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp @@ -12,6 +12,7 @@ #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" #include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" +#include "libGLESv2/renderer/d3d/ProgramD3D.h" #include "libGLESv2/renderer/d3d/VertexDataManager.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/VertexAttribute.h" @@ -137,7 +138,16 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl { gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS]; GetInputLayout(attributes, shaderInputLayout); - ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout)); + ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); + + ShaderExecutable *shader = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader); + if (error.isError()) + { + return error; + } + + ShaderExecutable *shader11 = ShaderExecutable11::makeShaderExecutable11(shader); D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS]; for (unsigned int j = 0; j < ilKey.elementCount; ++j) @@ -145,7 +155,7 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl descs[j] = ilKey.elements[j].desc; } - HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout); + HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp index a4e84f91c2..6a3d3475ee 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -33,12 +33,38 @@ namespace rx PixelTransfer11::PixelTransfer11(Renderer11 *renderer) : mRenderer(renderer), + mResourcesLoaded(false), mBufferToTextureVS(NULL), mBufferToTextureGS(NULL), mParamsConstantBuffer(NULL), mCopyRasterizerState(NULL), mCopyDepthStencilState(NULL) { +} + +PixelTransfer11::~PixelTransfer11() +{ + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + SafeRelease(shaderMapIt->second); + } + + mBufferToTexturePSMap.clear(); + + SafeRelease(mBufferToTextureVS); + SafeRelease(mBufferToTextureGS); + SafeRelease(mParamsConstantBuffer); + SafeRelease(mCopyRasterizerState); + SafeRelease(mCopyDepthStencilState); +} + +gl::Error PixelTransfer11::loadResources() +{ + if (mResourcesLoaded) + { + return gl::Error(GL_NO_ERROR); + } + HRESULT result = S_OK; ID3D11Device *device = mRenderer->getDevice(); @@ -56,6 +82,10 @@ PixelTransfer11::PixelTransfer11(Renderer11 *renderer) result = device->CreateRasterizerState(&rasterDesc, &mCopyRasterizerState); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer rasterizer state, result: 0x%X.", result); + } D3D11_DEPTH_STENCIL_DESC depthStencilDesc; depthStencilDesc.DepthEnable = true; @@ -75,9 +105,13 @@ PixelTransfer11::PixelTransfer11(Renderer11 *renderer) result = device->CreateDepthStencilState(&depthStencilDesc, &mCopyDepthStencilState); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer depth stencil state, result: 0x%X.", result); + } D3D11_BUFFER_DESC constantBufferDesc = { 0 }; - constantBufferDesc.ByteWidth = rx::roundUp(sizeof(CopyShaderParams), 32u); + constantBufferDesc.ByteWidth = roundUp(sizeof(CopyShaderParams), 32u); constantBufferDesc.Usage = D3D11_USAGE_DYNAMIC; constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; constantBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; @@ -86,34 +120,39 @@ PixelTransfer11::PixelTransfer11(Renderer11 *renderer) result = device->CreateBuffer(&constantBufferDesc, NULL, &mParamsConstantBuffer); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal pixel transfer constant buffer, result: 0x%X.", result); + } d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); + // init shaders + mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); + if (!mBufferToTextureVS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); + } + + if (!mRenderer->isLevel9()) + { + mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); + if (!mBufferToTextureGS) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); + } + } + + gl::Error error = buildShaderMap(); + if (error.isError()) + { + return error; + } + StructZero(&mParamsData); - // init shaders - if (mRenderer->isLevel9()) - return; + mResourcesLoaded = true; - mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); - mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); - - buildShaderMap(); -} - -PixelTransfer11::~PixelTransfer11() -{ - for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) - { - SafeRelease(shaderMapIt->second); - } - - mBufferToTexturePSMap.clear(); - - SafeRelease(mBufferToTextureVS); - SafeRelease(mBufferToTextureGS); - SafeRelease(mParamsConstantBuffer); - SafeRelease(mCopyRasterizerState); - SafeRelease(mCopyDepthStencilState); + return gl::Error(GL_NO_ERROR); } void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, @@ -138,17 +177,20 @@ void PixelTransfer11::setBufferToTextureCopyParams(const gl::Box &destArea, cons parametersOut->PositionScale[1] = -2.0f / static_cast(destSize.height); } -bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { + gl::Error error = loadResources(); + if (error.isError()) + { + return error; + } + gl::Extents destSize = destRenderTarget->getExtents(); - if (destArea.x < 0 || destArea.x + destArea.width > destSize.width || - destArea.y < 0 || destArea.y + destArea.height > destSize.height || - destArea.z < 0 || destArea.z + destArea.depth > destSize.depth ) - { - return false; - } + ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && + destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && + destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); @@ -177,7 +219,6 @@ bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, un ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - ID3D11ShaderResourceView *nullSRV = NULL; ID3D11Buffer *nullBuffer = NULL; UINT zero = 0; @@ -187,7 +228,7 @@ bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, un deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); deviceContext->GSSetShader(geometryShader, NULL, 0); deviceContext->PSSetShader(pixelShader, NULL, 0); - deviceContext->PSSetShaderResources(0, 1, &bufferSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); deviceContext->IASetInputLayout(NULL); deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); @@ -220,21 +261,32 @@ bool PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, un deviceContext->Draw(numPixels, 0); // Unbind textures and render targets and vertex buffer - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); mRenderer->markAllStateDirty(); - return true; + return gl::Error(GL_NO_ERROR); } -void PixelTransfer11::buildShaderMap() +gl::Error PixelTransfer11::buildShaderMap() { ID3D11Device *device = mRenderer->getDevice(); mBufferToTexturePSMap[GL_FLOAT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4F, "BufferToTexture RGBA ps"); mBufferToTexturePSMap[GL_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4I, "BufferToTexture RGBA-I ps"); mBufferToTexturePSMap[GL_UNSIGNED_INT] = d3d11::CompilePS(device, g_PS_BufferToTexture_4UI, "BufferToTexture RGBA-UI ps"); + + // Check that all the shaders were created successfully + for (auto shaderMapIt = mBufferToTexturePSMap.begin(); shaderMapIt != mBufferToTexturePSMap.end(); shaderMapIt++) + { + if (shaderMapIt->second == NULL) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture pixel shader."); + } + } + + return gl::Error(GL_NO_ERROR); } ID3D11PixelShader *PixelTransfer11::findBufferToTexturePS(GLenum internalFormat) const diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h index ed1a3ae1d0..29552140bb 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h @@ -11,6 +11,8 @@ #ifndef LIBGLESV2_PIXELTRANSFER11_H_ #define LIBGLESV2_PIXELTRANSFER11_H_ +#include "libGLESv2/Error.h" + #include "common/platform.h" #include @@ -38,15 +40,13 @@ class PixelTransfer11 explicit PixelTransfer11(Renderer11 *renderer); ~PixelTransfer11(); - static bool supportsBufferToTextureCopy(GLenum internalFormat); - // unpack: the source buffer is stored in the unpack state, and buffer strides // offset: the start of the data within the unpack buffer // destRenderTarget: individual slice/layer of a target texture // destinationFormat/sourcePixelsType: determines shaders + shader parameters // destArea: the sub-section of destRenderTarget to copy to - bool copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + gl::Error copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); private: @@ -65,11 +65,13 @@ class PixelTransfer11 static void setBufferToTextureCopyParams(const gl::Box &destArea, const gl::Extents &destSize, GLenum internalFormat, const gl::PixelUnpackState &unpack, unsigned int offset, CopyShaderParams *parametersOut); - void buildShaderMap(); + gl::Error loadResources(); + gl::Error buildShaderMap(); ID3D11PixelShader *findBufferToTexturePS(GLenum internalFormat) const; Renderer11 *mRenderer; + bool mResourcesLoaded; std::map mBufferToTexturePSMap; ID3D11VertexShader *mBufferToTextureVS; ID3D11GeometryShader *mBufferToTextureGS; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp index 7109be3e28..17ab1f8ab3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.cpp @@ -10,13 +10,14 @@ #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/main.h" +#include "common/utilities.h" #include namespace rx { -Query11::Query11(rx::Renderer11 *renderer, GLenum type) +Query11::Query11(Renderer11 *renderer, GLenum type) : QueryImpl(type), mResult(0), mQueryFinished(false), diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h index 822f2542ee..f9ff467873 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Query11.h @@ -18,7 +18,7 @@ class Renderer11; class Query11 : public QueryImpl { public: - Query11(rx::Renderer11 *renderer, GLenum type); + Query11(Renderer11 *renderer, GLenum type); virtual ~Query11(); virtual gl::Error begin(); @@ -35,7 +35,7 @@ class Query11 : public QueryImpl bool mQueryFinished; - rx::Renderer11 *mRenderer; + Renderer11 *mRenderer; ID3D11Query *mQuery; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp index 71b931f27e..ab4f60bd98 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.cpp @@ -38,11 +38,14 @@ const unsigned int RenderStateCache::kMaxRasterizerStates = 4096; const unsigned int RenderStateCache::kMaxDepthStencilStates = 4096; const unsigned int RenderStateCache::kMaxSamplerStates = 4096; -RenderStateCache::RenderStateCache() : mDevice(NULL), mCounter(0), - mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), - mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), - mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), - mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) +RenderStateCache::RenderStateCache(Renderer11 *renderer) + : mRenderer(renderer), + mDevice(NULL), + mCounter(0), + mBlendStateCache(kMaxBlendStates, hashBlendState, compareBlendStates), + mRasterizerStateCache(kMaxRasterizerStates, hashRasterizerState, compareRasterizerStates), + mDepthStencilStateCache(kMaxDepthStencilStates, hashDepthStencilState, compareDepthStencilStates), + mSamplerStateCache(kMaxSamplerStates, hashSamplerState, compareSamplerStates) { } @@ -89,7 +92,7 @@ gl::Error RenderStateCache::getBlendState(const gl::Framebuffer *framebuffer, co bool mrt = false; - const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(); + const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(mRenderer->getWorkarounds()); BlendStateKey key = { 0 }; key.blendState = blendState; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h index d5471a3061..dfd1d84265 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderStateCache.h @@ -28,7 +28,7 @@ class Renderer11; class RenderStateCache { public: - RenderStateCache(); + RenderStateCache(Renderer11 *renderer); virtual ~RenderStateCache(); void initialize(ID3D11Device *device); @@ -42,6 +42,7 @@ class RenderStateCache private: DISALLOW_COPY_AND_ASSIGN(RenderStateCache); + Renderer11 *mRenderer; unsigned long long mCounter; // Blend state cache diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp index 3041f21faa..aff3453492 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.cpp @@ -10,6 +10,7 @@ #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" +#include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/main.h" @@ -176,246 +177,10 @@ static unsigned int getDSVSubresourceIndex(ID3D11Resource *resource, ID3D11Depth return D3D11CalcSubresource(mipSlice, arraySlice, mipLevels); } -RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, - ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) -{ - mRenderer = Renderer11::makeRenderer11(renderer); - - mTexture = resource; - if (mTexture) - { - mTexture->AddRef(); - } - - mRenderTarget = rtv; - if (mRenderTarget) - { - mRenderTarget->AddRef(); - } - - mDepthStencil = NULL; - - mShaderResource = srv; - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - mSubresourceIndex = 0; - - if (mRenderTarget && mTexture) - { - D3D11_RENDER_TARGET_VIEW_DESC desc; - mRenderTarget->GetDesc(&desc); - - unsigned int mipLevels, samples; - getTextureProperties(mTexture, &mipLevels, &samples); - - mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); - mWidth = width; - mHeight = height; - mDepth = depth; - mSamples = samples; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); - mInternalFormat = dxgiFormatInfo.internalFormat; - mActualFormat = dxgiFormatInfo.internalFormat; - } -} - -RenderTarget11::RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, - ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth) -{ - mRenderer = Renderer11::makeRenderer11(renderer); - - mTexture = resource; - if (mTexture) - { - mTexture->AddRef(); - } - - mRenderTarget = NULL; - - mDepthStencil = dsv; - if (mDepthStencil) - { - mDepthStencil->AddRef(); - } - - mShaderResource = srv; - if (mShaderResource) - { - mShaderResource->AddRef(); - } - - mSubresourceIndex = 0; - - if (mDepthStencil && mTexture) - { - D3D11_DEPTH_STENCIL_VIEW_DESC desc; - mDepthStencil->GetDesc(&desc); - - unsigned int mipLevels, samples; - getTextureProperties(mTexture, &mipLevels, &samples); - - mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); - mWidth = width; - mHeight = height; - mDepth = depth; - mSamples = samples; - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); - mInternalFormat = dxgiFormatInfo.internalFormat; - mActualFormat = dxgiFormatInfo.internalFormat; - } -} - -RenderTarget11::RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) -{ - mRenderer = Renderer11::makeRenderer11(renderer); - mTexture = NULL; - mRenderTarget = NULL; - mDepthStencil = NULL; - mShaderResource = NULL; - - const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalFormat); - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(formatInfo.texFormat); - - const gl::TextureCaps &textureCaps = mRenderer->getRendererTextureCaps().get(internalFormat); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); - - if (width > 0 && height > 0) - { - // Create texture resource - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = formatInfo.texFormat; - desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - // If a rendertarget or depthstencil format exists for this texture format, - // we'll flag it to allow binding that way. Shader resource views are a little - // more complicated. - bool bindRTV = false, bindDSV = false, bindSRV = false; - bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); - bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); - if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) - { - // Multisample targets flagged for binding as depth stencil cannot also be - // flagged for binding as SRV, so make certain not to add the SRV flag for - // these targets. - bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); - } - - desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | - (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | - (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); - - ID3D11Device *device = mRenderer->getDevice(); - ID3D11Texture2D *texture = NULL; - HRESULT result = device->CreateTexture2D(&desc, NULL, &texture); - mTexture = texture; - - if (result == E_OUTOFMEMORY) - { - gl::error(GL_OUT_OF_MEMORY); - return; - } - ASSERT(SUCCEEDED(result)); - - if (bindSRV) - { - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = formatInfo.srvFormat; - srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = 1; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &mShaderResource); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(mTexture); - gl::error(GL_OUT_OF_MEMORY); - return; - } - ASSERT(SUCCEEDED(result)); - } - - if (bindDSV) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = formatInfo.dsvFormat; - dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; - dsvDesc.Texture2D.MipSlice = 0; - dsvDesc.Flags = 0; - result = device->CreateDepthStencilView(mTexture, &dsvDesc, &mDepthStencil); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(mTexture); - SafeRelease(mShaderResource); - gl::error(GL_OUT_OF_MEMORY); - return; - } - ASSERT(SUCCEEDED(result)); - } - - if (bindRTV) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = formatInfo.rtvFormat; - rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; - rtvDesc.Texture2D.MipSlice = 0; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &mRenderTarget); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(mTexture); - SafeRelease(mShaderResource); - SafeRelease(mDepthStencil); - gl::error(GL_OUT_OF_MEMORY); - return; - } - ASSERT(SUCCEEDED(result)); - - if (formatInfo.dataInitializerFunction != NULL) - { - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; - context->ClearRenderTargetView(mRenderTarget, clearValues); - } - } - } - - - mWidth = width; - mHeight = height; - mDepth = 1; - mInternalFormat = internalFormat; - mSamples = supportedSamples; - mActualFormat = dxgiFormatInfo.internalFormat; - mSubresourceIndex = D3D11CalcSubresource(0, 0, 1); -} - -RenderTarget11::~RenderTarget11() -{ - SafeRelease(mTexture); - SafeRelease(mRenderTarget); - SafeRelease(mDepthStencil); - SafeRelease(mShaderResource); -} - RenderTarget11 *RenderTarget11::makeRenderTarget11(RenderTarget *target) { - ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget11*, target)); - return static_cast(target); + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget11*, target)); + return static_cast(target); } void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) @@ -423,29 +188,217 @@ void RenderTarget11::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) // Currently a no-op } -ID3D11Resource *RenderTarget11::getTexture() const +TextureRenderTarget11::TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mActualFormat(internalFormat), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(rtv), + mDepthStencil(NULL), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mRenderTarget && mTexture) + { + mSubresourceIndex = getRTVSubresourceIndex(mTexture, mRenderTarget); + + D3D11_RENDER_TARGET_VIEW_DESC desc; + mRenderTarget->GetDesc(&desc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); + mActualFormat = dxgiFormatInfo.internalFormat; + } +} + +TextureRenderTarget11::TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mActualFormat(internalFormat), + mSamples(samples), + mSubresourceIndex(0), + mTexture(resource), + mRenderTarget(NULL), + mDepthStencil(dsv), + mShaderResource(srv) +{ + if (mTexture) + { + mTexture->AddRef(); + } + + if (mDepthStencil) + { + mDepthStencil->AddRef(); + } + + if (mShaderResource) + { + mShaderResource->AddRef(); + } + + if (mDepthStencil && mTexture) + { + mSubresourceIndex = getDSVSubresourceIndex(mTexture, mDepthStencil); + + D3D11_DEPTH_STENCIL_VIEW_DESC desc; + mDepthStencil->GetDesc(&desc); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(desc.Format); + mActualFormat = dxgiFormatInfo.internalFormat; + } +} + +TextureRenderTarget11::~TextureRenderTarget11() +{ + SafeRelease(mTexture); + SafeRelease(mRenderTarget); + SafeRelease(mDepthStencil); + SafeRelease(mShaderResource); +} + +ID3D11Resource *TextureRenderTarget11::getTexture() const { return mTexture; } -ID3D11RenderTargetView *RenderTarget11::getRenderTargetView() const +ID3D11RenderTargetView *TextureRenderTarget11::getRenderTargetView() const { return mRenderTarget; } -ID3D11DepthStencilView *RenderTarget11::getDepthStencilView() const +ID3D11DepthStencilView *TextureRenderTarget11::getDepthStencilView() const { return mDepthStencil; } -ID3D11ShaderResourceView *RenderTarget11::getShaderResourceView() const +ID3D11ShaderResourceView *TextureRenderTarget11::getShaderResourceView() const { return mShaderResource; } -unsigned int RenderTarget11::getSubresourceIndex() const +GLsizei TextureRenderTarget11::getWidth() const +{ + return mWidth; +} + +GLsizei TextureRenderTarget11::getHeight() const +{ + return mHeight; +} + +GLsizei TextureRenderTarget11::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget11::getInternalFormat() const +{ + return mInternalFormat; +} + +GLenum TextureRenderTarget11::getActualFormat() const +{ + return mActualFormat; +} + +GLsizei TextureRenderTarget11::getSamples() const +{ + return mSamples; +} + +unsigned int TextureRenderTarget11::getSubresourceIndex() const { return mSubresourceIndex; } + +SurfaceRenderTarget11::SurfaceRenderTarget11(SwapChain11 *swapChain, bool depth) + : mSwapChain(swapChain), + mDepth(depth) +{ + ASSERT(mSwapChain); +} + +SurfaceRenderTarget11::~SurfaceRenderTarget11() +{ +} + +GLsizei SurfaceRenderTarget11::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget11::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget11::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget11::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLenum SurfaceRenderTarget11::getActualFormat() const +{ + return d3d11::GetDXGIFormatInfo(d3d11::GetTextureFormatInfo(getInternalFormat()).texFormat).internalFormat; +} + +GLsizei SurfaceRenderTarget11::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +ID3D11Resource *SurfaceRenderTarget11::getTexture() const +{ + return (mDepth ? mSwapChain->getDepthStencilTexture() : mSwapChain->getOffscreenTexture()); +} + +ID3D11RenderTargetView *SurfaceRenderTarget11::getRenderTargetView() const +{ + return (mDepth ? NULL : mSwapChain->getRenderTarget()); +} + +ID3D11DepthStencilView *SurfaceRenderTarget11::getDepthStencilView() const +{ + return (mDepth ? mSwapChain->getDepthStencil() : NULL); +} + +ID3D11ShaderResourceView *SurfaceRenderTarget11::getShaderResourceView() const +{ + return (mDepth ? mSwapChain->getDepthStencilShaderResource() : mSwapChain->getRenderTargetShaderResource()); +} + +unsigned int SurfaceRenderTarget11::getSubresourceIndex() const +{ + return 0; +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h index 82182957af..c7babdda3f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/RenderTarget11.h @@ -14,39 +14,95 @@ namespace rx { -class Renderer; -class Renderer11; +class SwapChain11; class RenderTarget11 : public RenderTarget { public: - // RenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them - RenderTarget11(Renderer *renderer, ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); - RenderTarget11(Renderer *renderer, ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, GLsizei width, GLsizei height, GLsizei depth); - RenderTarget11(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); - virtual ~RenderTarget11(); + RenderTarget11() { } + virtual ~RenderTarget11() { } static RenderTarget11 *makeRenderTarget11(RenderTarget *renderTarget); - virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) override; - ID3D11Resource *getTexture() const; - ID3D11RenderTargetView *getRenderTargetView() const; - ID3D11DepthStencilView *getDepthStencilView() const; - ID3D11ShaderResourceView *getShaderResourceView() const; + virtual ID3D11Resource *getTexture() const = 0; + virtual ID3D11RenderTargetView *getRenderTargetView() const = 0; + virtual ID3D11DepthStencilView *getDepthStencilView() const = 0; + virtual ID3D11ShaderResourceView *getShaderResourceView() const = 0; - unsigned int getSubresourceIndex() const; + virtual unsigned int getSubresourceIndex() const = 0; private: DISALLOW_COPY_AND_ASSIGN(RenderTarget11); +}; + +class TextureRenderTarget11 : public RenderTarget11 +{ + public: + // TextureRenderTarget11 takes ownership of any D3D11 resources it is given and will AddRef them + TextureRenderTarget11(ID3D11RenderTargetView *rtv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + TextureRenderTarget11(ID3D11DepthStencilView *dsv, ID3D11Resource *resource, ID3D11ShaderResourceView *srv, + GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei samples); + virtual ~TextureRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLenum getActualFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureRenderTarget11); + + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + GLenum mActualFormat; + GLsizei mSamples; unsigned int mSubresourceIndex; ID3D11Resource *mTexture; ID3D11RenderTargetView *mRenderTarget; ID3D11DepthStencilView *mDepthStencil; ID3D11ShaderResourceView *mShaderResource; +}; - Renderer11 *mRenderer; +class SurfaceRenderTarget11 : public RenderTarget11 +{ + public: + SurfaceRenderTarget11(SwapChain11 *swapChain, bool depth); + virtual ~SurfaceRenderTarget11(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLenum getActualFormat() const override; + GLsizei getSamples() const override; + + ID3D11Resource *getTexture() const override; + ID3D11RenderTargetView *getRenderTargetView() const override; + ID3D11DepthStencilView *getDepthStencilView() const override; + ID3D11ShaderResourceView *getShaderResourceView() const override; + + unsigned int getSubresourceIndex() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(SurfaceRenderTarget11); + + SwapChain11 *mSwapChain; + bool mDepth; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp index b29b2ef910..e6d7f3025b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp @@ -6,12 +6,12 @@ // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. -#include "common/platform.h" #include "libGLESv2/main.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Framebuffer.h" +#include "libGLESv2/State.h" #include "libGLESv2/renderer/d3d/ProgramD3D.h" #include "libGLESv2/renderer/d3d/ShaderD3D.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" @@ -36,10 +36,12 @@ #include "libGLESv2/renderer/d3d/d3d11/PixelTransfer11.h" #include "libGLESv2/renderer/d3d/d3d11/VertexArray11.h" #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h" +#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" #include "libEGL/Display.h" #include "common/utilities.h" +#include "common/tls.h" #include @@ -59,6 +61,9 @@ namespace rx { + +namespace +{ static const DXGI_FORMAT RenderTargetFormats[] = { DXGI_FORMAT_B8G8R8A8_UNORM, @@ -77,10 +82,22 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 = 16 }; -Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay) - : Renderer(display), +// Does *not* increment the resource ref count!! +ID3D11Resource *GetSRVResource(ID3D11ShaderResourceView *srv) +{ + ID3D11Resource *resource = NULL; + ASSERT(srv); + srv->GetResource(&resource); + resource->Release(); + return resource; +} + +} + +Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes) + : RendererD3D(display), mDc(hDc), - mRequestedDisplay(requestedDisplay) + mStateCache(this) { mVertexDataManager = NULL; mIndexDataManager = NULL; @@ -112,6 +129,50 @@ Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint r mAppliedGeometryShader = NULL; mCurPointGeometryShader = NULL; mAppliedPixelShader = NULL; + + EGLint requestedMajorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE); + EGLint requestedMinorVersion = attributes.get(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE); + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 11) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_11_0); + } + } + + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 10) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_1); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 0) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_10_0); + } + } + +#if !defined(ANGLE_ENABLE_D3D9) + if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) + { + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); + } + if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) + { + mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); + } + } +#endif + + mDriverType = (attributes.get(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_FALSE) == EGL_TRUE) ? D3D_DRIVER_TYPE_WARP + : D3D_DRIVER_TYPE_HARDWARE; } Renderer11::~Renderer11() @@ -121,8 +182,8 @@ Renderer11::~Renderer11() Renderer11 *Renderer11::makeRenderer11(Renderer *renderer) { - ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer11*, renderer)); - return static_cast(renderer); + ASSERT(HAS_DYNAMIC_TYPE(Renderer11*, renderer)); + return static_cast(renderer); } #ifndef __d3d11_1_h__ @@ -136,7 +197,7 @@ EGLint Renderer11::initialize() return EGL_NOT_INITIALIZED; } -#if !defined(ANGLE_PLATFORM_WINRT) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); @@ -157,33 +218,14 @@ EGLint Renderer11::initialize() } #endif - D3D_FEATURE_LEVEL featureLevels[] = - { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, -#if !defined(ANGLE_ENABLE_D3D9) - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1, -#endif - }; - - D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE; - if (mRequestedDisplay == EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE) - { - driverType = D3D_DRIVER_TYPE_WARP; - } - HRESULT result = S_OK; - #ifdef _DEBUG result = D3D11CreateDevice(NULL, - driverType, + mDriverType, NULL, D3D11_CREATE_DEVICE_DEBUG, - featureLevels, - ArraySize(featureLevels), + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, @@ -198,11 +240,11 @@ EGLint Renderer11::initialize() #endif { result = D3D11CreateDevice(NULL, - driverType, + mDriverType, NULL, 0, - featureLevels, - ArraySize(featureLevels), + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), D3D11_SDK_VERSION, &mDevice, &mFeatureLevel, @@ -215,7 +257,18 @@ EGLint Renderer11::initialize() } } -#if !ANGLE_SKIP_DXGI_1_2_CHECK && !defined(ANGLE_PLATFORM_WINRT) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) + static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); + if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) + { + ID3D10Multithread *multithread; + result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread)); + ASSERT(SUCCEEDED(result)); + result = multithread->SetMultithreadProtected(true); + ASSERT(SUCCEEDED(result)); + multithread->Release(); + } +#if !ANGLE_SKIP_DXGI_1_2_CHECK // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. // The easiest way to check is to query for a IDXGIDevice2. bool requireDXGI1_2 = false; @@ -244,13 +297,10 @@ EGLint Renderer11::initialize() SafeRelease(dxgiDevice2); } #endif - -#if !defined(ANGLE_PLATFORM_WINRT) - IDXGIDevice *dxgiDevice = NULL; -#else - IDXGIDevice1 *dxgiDevice = NULL; #endif - result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); + + IDXGIDevice *dxgiDevice = NULL; + result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); if (FAILED(result)) { @@ -281,9 +331,9 @@ EGLint Renderer11::initialize() } // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log -#if !defined(__MINGW32__) && defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) +#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) ID3D11InfoQueue *infoQueue; - result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); + result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); if (SUCCEEDED(result)) { @@ -301,19 +351,6 @@ EGLint Renderer11::initialize() } #endif -#if !defined(ANGLE_PLATFORM_WINRT) - static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); - if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) - { - ID3D10Multithread *multithread; - result = mDevice->QueryInterface(IID_PPV_ARGS(&multithread)); - ASSERT(SUCCEEDED(result)); - result = multithread->SetMultithreadProtected(true); - ASSERT(SUCCEEDED(result)); - multithread->Release(); - } -#endif - initializeDevice(); return EGL_SUCCESS; @@ -394,7 +431,7 @@ void Renderer11::deleteConfigs(ConfigDesc *configDescList) delete [] (configDescList); } -void Renderer11::sync(bool block) +gl::Error Renderer11::sync(bool block) { if (block) { @@ -408,6 +445,10 @@ void Renderer11::sync(bool block) result = mDevice->CreateQuery(&queryDesc, &mSyncQuery); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create event query, result: 0x%X.", result); + } } mDeviceContext->End(mSyncQuery); @@ -416,13 +457,17 @@ void Renderer11::sync(bool block) do { result = mDeviceContext->GetData(mSyncQuery, NULL, 0, D3D11_ASYNC_GETDATA_DONOTFLUSH); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } // Keep polling, but allow other threads to do something useful first Sleep(0); if (testDeviceLost(true)) { - return; + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while waiting for sync."); } } while (result == S_FALSE); @@ -431,22 +476,26 @@ void Renderer11::sync(bool block) { mDeviceContext->Flush(); } + + return gl::Error(GL_NO_ERROR); } -SwapChain *Renderer11::createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +SwapChain *Renderer11::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) { - return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat); + return new SwapChain11(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); } gl::Error Renderer11::generateSwizzle(gl::Texture *texture) { if (texture) { - TextureStorage *texStorage = texture->getNativeTexture(); + TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); + ASSERT(textureD3D); + + TextureStorage *texStorage = textureD3D->getNativeTexture(); if (texStorage) { TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); - gl::Error error = storage11->generateSwizzles(texture->getSamplerState().swizzleRed, texture->getSamplerState().swizzleGreen, texture->getSamplerState().swizzleBlue, @@ -461,16 +510,21 @@ gl::Error Renderer11::generateSwizzle(gl::Texture *texture) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) +gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerStateParam) { + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); + gl::SamplerState samplerStateInternal = samplerStateParam; + samplerStateInternal.baseLevel += textureD3D->getNativeTexture()->getTopLevel(); + if (type == gl::SAMPLER_PIXEL) { ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); - if (mForceSetPixelSamplerStates[index] || memcmp(&samplerState, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) + if (mForceSetPixelSamplerStates[index] || memcmp(&samplerStateInternal, &mCurPixelSamplerStates[index], sizeof(gl::SamplerState)) != 0) { ID3D11SamplerState *dxSamplerState = NULL; - gl::Error error = mStateCache.getSamplerState(samplerState, &dxSamplerState); + gl::Error error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); if (error.isError()) { return error; @@ -479,7 +533,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, const gl: ASSERT(dxSamplerState != NULL); mDeviceContext->PSSetSamplers(index, 1, &dxSamplerState); - mCurPixelSamplerStates[index] = samplerState; + mCurPixelSamplerStates[index] = samplerStateInternal; } mForceSetPixelSamplerStates[index] = false; @@ -488,10 +542,10 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, const gl: { ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); - if (mForceSetVertexSamplerStates[index] || memcmp(&samplerState, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) + if (mForceSetVertexSamplerStates[index] || memcmp(&samplerStateInternal, &mCurVertexSamplerStates[index], sizeof(gl::SamplerState)) != 0) { ID3D11SamplerState *dxSamplerState = NULL; - gl::Error error = mStateCache.getSamplerState(samplerState, &dxSamplerState); + gl::Error error = mStateCache.getSamplerState(samplerStateInternal, &dxSamplerState); if (error.isError()) { return error; @@ -500,7 +554,7 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, const gl: ASSERT(dxSamplerState != NULL); mDeviceContext->VSSetSamplers(index, 1, &dxSamplerState); - mCurVertexSamplerStates[index] = samplerState; + mCurVertexSamplerStates[index] = samplerStateInternal; } mForceSetVertexSamplerStates[index] = false; @@ -513,50 +567,36 @@ gl::Error Renderer11::setSamplerState(gl::SamplerType type, int index, const gl: gl::Error Renderer11::setTexture(gl::SamplerType type, int index, gl::Texture *texture) { ID3D11ShaderResourceView *textureSRV = NULL; - bool forceSetTexture = false; if (texture) { - TextureD3D* textureImpl = TextureD3D::makeTextureD3D(texture->getImplementation()); + TextureD3D *textureImpl = TextureD3D::makeTextureD3D(texture->getImplementation()); TextureStorage *texStorage = textureImpl->getNativeTexture(); ASSERT(texStorage != NULL); TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(texStorage); - gl::SamplerState samplerState; - texture->getSamplerStateWithNativeOffset(&samplerState); - textureSRV = storage11->getSRV(samplerState); + + // Make sure to add the level offset for our tiny compressed texture workaround + gl::SamplerState samplerState = texture->getSamplerState(); + samplerState.baseLevel += storage11->getTopLevel(); + + gl::Error error = storage11->getSRV(samplerState, &textureSRV); + if (error.isError()) + { + return error; + } // If we get NULL back from getSRV here, something went wrong in the texture class and we're unexpectedly // missing the shader resource view ASSERT(textureSRV != NULL); - forceSetTexture = textureImpl->hasDirtyImages(); textureImpl->resetDirty(); } - if (type == gl::SAMPLER_PIXEL) - { - ASSERT(static_cast(index) < getRendererCaps().maxTextureImageUnits); + ASSERT((type == gl::SAMPLER_PIXEL && static_cast(index) < getRendererCaps().maxTextureImageUnits) || + (type == gl::SAMPLER_VERTEX && static_cast(index) < getRendererCaps().maxVertexTextureImageUnits)); - if (forceSetTexture || mCurPixelSRVs[index] != textureSRV) - { - mDeviceContext->PSSetShaderResources(index, 1, &textureSRV); - } - - mCurPixelSRVs[index] = textureSRV; - } - else if (type == gl::SAMPLER_VERTEX) - { - ASSERT(static_cast(index) < getRendererCaps().maxVertexTextureImageUnits); - - if (forceSetTexture || mCurVertexSRVs[index] != textureSRV) - { - mDeviceContext->VSSetShaderResources(index, 1, &textureSRV); - } - - mCurVertexSRVs[index] = textureSRV; - } - else UNREACHABLE(); + setShaderResource(type, index, textureSRV); return gl::Error(GL_NO_ERROR); } @@ -631,7 +671,7 @@ gl::Error Renderer11::setRasterizerState(const gl::RasterizerState &rasterState) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, +gl::Error Renderer11::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask) { if (mForceSetBlendState || @@ -831,7 +871,22 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) return count >= minCount; } -gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) +void Renderer11::unsetSRVsWithResource(gl::SamplerType samplerType, const ID3D11Resource *resource) +{ + std::vector ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) + { + ID3D11ShaderResourceView *srv = currentSRVs[resourceIndex]; + + if (srv && GetSRVResource(srv) == resource) + { + setShaderResource(samplerType, static_cast(resourceIndex), NULL); + } + } +} + +gl::Error Renderer11::applyRenderTarget(const gl::Framebuffer *framebuffer) { // Get the color render buffer and serial // Also extract the render target dimensions and view @@ -842,7 +897,7 @@ gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) ID3D11RenderTargetView* framebufferRTVs[gl::IMPLEMENTATION_MAX_DRAW_BUFFERS] = {NULL}; bool missingColorRenderTarget = true; - const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(); + const gl::ColorbufferInfo &colorbuffers = framebuffer->getColorbuffersForRender(getWorkarounds()); for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment) { @@ -863,17 +918,16 @@ gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) renderTargetSerials[colorAttachment] = GetAttachmentSerial(colorbuffer); // Extract the render target dimensions and view - RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (!renderTarget) + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target pointer unexpectedly null."); + return error; } + ASSERT(renderTarget); framebufferRTVs[colorAttachment] = renderTarget->getRenderTargetView(); - if (!framebufferRTVs[colorAttachment]) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target view pointer unexpectedly null."); - } + ASSERT(framebufferRTVs[colorAttachment]); if (missingColorRenderTarget) { @@ -883,8 +937,12 @@ gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) missingColorRenderTarget = false; } - // TODO: Detect if this color buffer is already bound as a texture and unbind it first to prevent - // D3D11 warnings. +#if !defined(NDEBUG) + // Unbind render target SRVs from the shader here to prevent D3D11 warnings. + ID3D11Resource *renderTargetResource = renderTarget->getTexture(); + unsetSRVsWithResource(gl::SAMPLER_VERTEX, renderTargetResource); + unsetSRVsWithResource(gl::SAMPLER_PIXEL, renderTargetResource); +#endif } } @@ -905,19 +963,17 @@ gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) ID3D11DepthStencilView* framebufferDSV = NULL; if (depthStencil) { - RenderTarget11 *depthStencilRenderTarget = d3d11::GetAttachmentRenderTarget(depthStencil); - if (!depthStencilRenderTarget) + RenderTarget11 *depthStencilRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); + if (error.isError()) { SafeRelease(framebufferRTVs); - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target pointer unexpectedly null."); + return error; } + ASSERT(depthStencilRenderTarget); framebufferDSV = depthStencilRenderTarget->getDepthStencilView(); - if (!framebufferDSV) - { - SafeRelease(framebufferRTVs); - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil view pointer unexpectedly null."); - } + ASSERT(framebufferDSV); // If there is no render buffer, the width, height and format values come from // the depth stencil @@ -964,17 +1020,16 @@ gl::Error Renderer11::applyRenderTarget(gl::Framebuffer *framebuffer) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) +gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); if (error.isError()) { return error; } - return mInputLayoutCache.applyVertexBuffers(attributes, programBinary); + return mInputLayoutCache.applyVertexBuffers(attributes, state.getCurrentProgramBinary()); } gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) @@ -1011,28 +1066,25 @@ gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elemen return gl::Error(GL_NO_ERROR); } -void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +void Renderer11::applyTransformFeedbackBuffers(const gl::State& state) { - ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + size_t numXFBBindings = state.getTransformFeedbackBufferIndexRange(); + ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS); + bool requiresUpdate = false; - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (size_t i = 0; i < numXFBBindings; i++) { - if (transformFeedbackBuffers[i]) + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + ID3D11Buffer *d3dBuffer = NULL; + if (curXFBBuffer) { - Buffer11 *storage = Buffer11::makeBuffer11(transformFeedbackBuffers[i]->getImplementation()); - ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); - - d3dBuffers[i] = buffer; - d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast(offsets[i]) : -1; - } - else - { - d3dBuffers[i] = NULL; - d3dOffsets[i] = 0; + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); } - if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i]) + // TODO: mAppliedTFBuffers and friends should also be kept in a vector. + if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i]) { requiresUpdate = true; } @@ -1040,12 +1092,29 @@ void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuff if (requiresUpdate) { - mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets); - for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++) + for (size_t i = 0; i < numXFBBindings; ++i) { - mAppliedTFBuffers[i] = d3dBuffers[i]; - mAppliedTFOffsets[i] = offsets[i]; + gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i); + GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i); + + if (curXFBBuffer) + { + Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation()); + ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK); + + mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer && mAppliedTFOffsets[i] != curXFBOffset) ? + static_cast(curXFBOffset) : -1; + mAppliedTFBuffers[i] = d3dBuffer; + } + else + { + mAppliedTFBuffers[i] = NULL; + mCurrentD3DOffsets[i] = 0; + } + mAppliedTFOffsets[i] = curXFBOffset; } + + mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets); } } @@ -1129,7 +1198,6 @@ gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, cons return gl::Error(GL_NO_ERROR); } } - template static void fillLineLoopIndices(GLenum type, GLsizei count, const GLvoid *indices, T *data) { @@ -1213,10 +1281,17 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { - gl::Buffer *indexBuffer = elementArrayBuffer; - BufferImpl *storage = indexBuffer->getImplementation(); + BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); intptr_t offset = reinterpret_cast(indices); - indices = static_cast(storage->getData()) + offset; + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; } // TODO: some level 9 hardware supports 32-bit indices; test and store support instead @@ -1291,10 +1366,17 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { - gl::Buffer *indexBuffer = elementArrayBuffer; - BufferImpl *storage = indexBuffer->getImplementation(); + BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); intptr_t offset = reinterpret_cast(indices); - indices = static_cast(storage->getData()) + offset; + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; } const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; @@ -1376,9 +1458,23 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive) { - ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); - ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); - ShaderExecutable *geometryExe = programBinary->getGeometryExecutable(); + ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); + + ShaderExecutable *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); + if (error.isError()) + { + return error; + } + + ShaderExecutable *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } + + ShaderExecutable *geometryExe = programD3D->getGeometryExecutable(); ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL); @@ -1433,16 +1529,14 @@ gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::V if (dirtyUniforms) { - programBinary->dirtyAllUniforms(); + programD3D->dirtyAllUniforms(); } return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) +gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) { - const std::vector &uniformArray = programBinary.getUniforms(); - unsigned int totalRegisterCountVS = 0; unsigned int totalRegisterCountPS = 0; @@ -1466,7 +1560,7 @@ gl::Error Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) } } - const ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary.getImplementation()); + const ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(&program); const UniformStorage11 *vertexUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getVertexUniformStorage()); const UniformStorage11 *fragmentUniformStorage = UniformStorage11::makeUniformStorage11(&programD3D->getFragmentUniformStorage()); ASSERT(vertexUniformStorage); @@ -1598,7 +1692,7 @@ gl::Error Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +gl::Error Renderer11::clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) { gl::Error error = mClear->clearFramebuffer(clearParams, frameBuffer); if (error.isError()) @@ -1626,14 +1720,12 @@ void Renderer11::markAllStateDirty() for (size_t vsamplerId = 0; vsamplerId < mForceSetVertexSamplerStates.size(); ++vsamplerId) { mForceSetVertexSamplerStates[vsamplerId] = true; - mCurVertexSRVs[vsamplerId] = NULL; } ASSERT(mForceSetPixelSamplerStates.size() == mCurPixelSRVs.size()); for (size_t fsamplerId = 0; fsamplerId < mForceSetPixelSamplerStates.size(); ++fsamplerId) { mForceSetPixelSamplerStates[fsamplerId] = true; - mCurPixelSRVs[fsamplerId] = NULL; } mForceSetBlendState = true; @@ -1746,32 +1838,20 @@ bool Renderer11::testDeviceResettable() return false; } - D3D_FEATURE_LEVEL featureLevels[] = - { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, -#if !defined(ANGLE_ENABLE_D3D9) - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1, -#endif - }; - ID3D11Device* dummyDevice; D3D_FEATURE_LEVEL dummyFeatureLevel; ID3D11DeviceContext* dummyContext; HRESULT result = D3D11CreateDevice(NULL, - D3D_DRIVER_TYPE_HARDWARE, + mDriverType, NULL, #if defined(_DEBUG) D3D11_CREATE_DEVICE_DEBUG, #else 0, #endif - featureLevels, - ArraySize(featureLevels), + mAvailableFeatureLevels.data(), + mAvailableFeatureLevels.size(), D3D11_SDK_VERSION, &dummyDevice, &dummyFeatureLevel, @@ -1939,119 +2019,37 @@ int Renderer11::getMaxSwapInterval() const return 4; } -bool Renderer11::copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source) -{ - if (source && dest) - { - TextureStorage11_2D *source11 = TextureStorage11_2D::makeTextureStorage11_2D(source); - TextureStorage11_2D *dest11 = TextureStorage11_2D::makeTextureStorage11_2D(dest); - - mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); - - dest11->invalidateSwizzleCache(); - - return true; - } - - return false; -} - -bool Renderer11::copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source) -{ - if (source && dest) - { - TextureStorage11_Cube *source11 = TextureStorage11_Cube::makeTextureStorage11_Cube(source); - TextureStorage11_Cube *dest11 = TextureStorage11_Cube::makeTextureStorage11_Cube(dest); - - mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); - - dest11->invalidateSwizzleCache(); - - return true; - } - - return false; -} - -bool Renderer11::copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source) -{ - if (source && dest) - { - TextureStorage11_3D *source11 = TextureStorage11_3D::makeTextureStorage11_3D(source); - TextureStorage11_3D *dest11 = TextureStorage11_3D::makeTextureStorage11_3D(dest); - - mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); - - dest11->invalidateSwizzleCache(); - - return true; - } - - return false; -} - -bool Renderer11::copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source) -{ - if (source && dest) - { - TextureStorage11_2DArray *source11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(source); - TextureStorage11_2DArray *dest11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(dest); - - mDeviceContext->CopyResource(dest11->getResource(), source11->getResource()); - - dest11->invalidateSwizzleCache(); - - return true; - } - - return false; -} - -bool Renderer11::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) +gl::Error Renderer11::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) { gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - if (!colorbuffer) - { - ERR("Failed to retrieve the color buffer from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(colorbuffer); - RenderTarget11 *sourceRenderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (!sourceRenderTarget) + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the render target from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(sourceRenderTarget); ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - if (!source) - { - ERR("Failed to retrieve the render target view from the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(source); TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage); - if (!storage11) - { - ERR("Failed to retrieve the texture storage from the destination."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::Make2D(level); - RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(index)); - if (!destRenderTarget) + RenderTarget *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the render target from the destination storage."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); - if (!dest) - { - ERR("Failed to retrieve the render target view from the destination render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); @@ -2061,59 +2059,48 @@ bool Renderer11::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle & // Use nearest filtering because source and destination are the same size for the direct // copy - bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, - destFormat, GL_NEAREST); + mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } storage11->invalidateSwizzleCacheLevel(level); - return ret; + return gl::Error(GL_NO_ERROR); } -bool Renderer11::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) +gl::Error Renderer11::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) { gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - if (!colorbuffer) - { - ERR("Failed to retrieve the color buffer from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(colorbuffer); - RenderTarget11 *sourceRenderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (!sourceRenderTarget) + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the render target from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(sourceRenderTarget); ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - if (!source) - { - ERR("Failed to retrieve the render target view from the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(source); TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage); - if (!storage11) - { - ERR("Failed to retrieve the texture storage from the destination."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(storage11); gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level); - RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(index)); - if (!destRenderTarget) + RenderTarget *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the render target from the destination storage."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); - if (!dest) - { - ERR("Failed to retrieve the render target view from the destination render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); @@ -2123,123 +2110,48 @@ bool Renderer11::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle // Use nearest filtering because source and destination are the same size for the direct // copy - bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, - destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } storage11->invalidateSwizzleCacheLevel(level); - return ret; + return gl::Error(GL_NO_ERROR); } -bool Renderer11::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) -{ - gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - if (!colorbuffer) - { - ERR("Failed to retrieve the color buffer from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - RenderTarget11 *sourceRenderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (!sourceRenderTarget) - { - ERR("Failed to retrieve the render target from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - if (!source) - { - ERR("Failed to retrieve the render target view from the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); - if (!storage11) - { - ERR("Failed to retrieve the texture storage from the destination."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - gl::ImageIndex index = gl::ImageIndex::Make3D(level, zOffset); - RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(index)); - if (!destRenderTarget) - { - ERR("Failed to retrieve the render target from the destination storage."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); - if (!dest) - { - ERR("Failed to retrieve the render target view from the destination render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); - - gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); - gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); - - // Use nearest filtering because source and destination are the same size for the direct - // copy - bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, - destFormat, GL_NEAREST); - - storage11->invalidateSwizzleCacheLevel(level); - - return ret; -} - -bool Renderer11::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, +gl::Error Renderer11::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) { gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); - if (!colorbuffer) - { - ERR("Failed to retrieve the color buffer from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(colorbuffer); - RenderTarget11 *sourceRenderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (!sourceRenderTarget) + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the render target from the frame buffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(sourceRenderTarget); ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); - if (!source) - { - ERR("Failed to retrieve the render target view from the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ASSERT(source); - TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); - if (!storage11) - { - SafeRelease(source); - ERR("Failed to retrieve the texture storage from the destination."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage); + ASSERT(storage11); - gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zOffset); - RenderTarget11 *destRenderTarget = RenderTarget11::makeRenderTarget11(storage11->getRenderTarget(index)); - if (!destRenderTarget) + gl::ImageIndex index = gl::ImageIndex::Make3D(level, zOffset); + RenderTarget *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) { - SafeRelease(source); - ERR("Failed to retrieve the render target from the destination storage."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(destRenderTarget); - ID3D11RenderTargetView *dest = destRenderTarget->getRenderTargetView(); - if (!dest) - { - ERR("Failed to retrieve the render target view from the destination render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); @@ -2249,12 +2161,66 @@ bool Renderer11::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectan // Use nearest filtering because source and destination are the same size for the direct // copy - bool ret = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, - destFormat, GL_NEAREST); + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } storage11->invalidateSwizzleCacheLevel(level); - return ret; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Renderer11::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) +{ + gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); + + RenderTarget11 *sourceRenderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &sourceRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(sourceRenderTarget); + + ID3D11ShaderResourceView *source = sourceRenderTarget->getShaderResourceView(); + ASSERT(source); + + TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage); + ASSERT(storage11); + + gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zOffset); + RenderTarget *destRenderTarget = NULL; + error = storage11->getRenderTarget(index, &destRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(destRenderTarget); + + ID3D11RenderTargetView *dest = RenderTarget11::makeRenderTarget11(destRenderTarget)->getRenderTargetView(); + ASSERT(dest); + + gl::Box sourceArea(sourceRect.x, sourceRect.y, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents sourceSize(sourceRenderTarget->getWidth(), sourceRenderTarget->getHeight(), 1); + + gl::Box destArea(xoffset, yoffset, 0, sourceRect.width, sourceRect.height, 1); + gl::Extents destSize(destRenderTarget->getWidth(), destRenderTarget->getHeight(), 1); + + // Use nearest filtering because source and destination are the same size for the direct + // copy + error = mBlit->copyTexture(source, sourceArea, sourceSize, dest, destArea, destSize, NULL, destFormat, GL_NEAREST); + if (error.isError()) + { + return error; + } + + storage11->invalidateSwizzleCacheLevel(level); + + return gl::Error(GL_NO_ERROR); } void Renderer11::unapplyRenderTargets() @@ -2277,39 +2243,150 @@ void Renderer11::setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView } } -RenderTarget *Renderer11::createRenderTarget(SwapChain *swapChain, bool depth) +gl::Error Renderer11::createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) { SwapChain11 *swapChain11 = SwapChain11::makeSwapChain11(swapChain); - RenderTarget11 *renderTarget = NULL; + *outRT = new SurfaceRenderTarget11(swapChain11, depth); + return gl::Error(GL_NO_ERROR); +} - if (depth) +gl::Error Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) +{ + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(format); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + if (width > 0 && height > 0) { - // Note: depth stencil may be NULL for 0 sized surfaces - renderTarget = new RenderTarget11(this, swapChain11->getDepthStencil(), - swapChain11->getDepthStencilTexture(), - swapChain11->getDepthStencilShaderResource(), - swapChain11->getWidth(), swapChain11->getHeight(), 1); + // Create texture resource + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = formatInfo.texFormat; + desc.SampleDesc.Count = (supportedSamples == 0) ? 1 : supportedSamples; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + // If a rendertarget or depthstencil format exists for this texture format, + // we'll flag it to allow binding that way. Shader resource views are a little + // more complicated. + bool bindRTV = false, bindDSV = false, bindSRV = false; + bindRTV = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN); + bindDSV = (formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN); + if (formatInfo.srvFormat != DXGI_FORMAT_UNKNOWN) + { + // Multisample targets flagged for binding as depth stencil cannot also be + // flagged for binding as SRV, so make certain not to add the SRV flag for + // these targets. + bindSRV = !(formatInfo.dsvFormat != DXGI_FORMAT_UNKNOWN && desc.SampleDesc.Count > 1); + } + + desc.BindFlags = (bindRTV ? D3D11_BIND_RENDER_TARGET : 0) | + (bindDSV ? D3D11_BIND_DEPTH_STENCIL : 0) | + (bindSRV ? D3D11_BIND_SHADER_RESOURCE : 0); + + // The format must be either an RTV or a DSV + ASSERT(bindRTV != bindDSV); + + ID3D11Texture2D *texture = NULL; + HRESULT result = mDevice->CreateTexture2D(&desc, NULL, &texture); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target texture, result: 0x%X.", result); + } + + ID3D11ShaderResourceView *srv = NULL; + if (bindSRV) + { + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = formatInfo.srvFormat; + srvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_SRV_DIMENSION_TEXTURE2D : D3D11_SRV_DIMENSION_TEXTURE2DMS; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = 1; + + result = mDevice->CreateShaderResourceView(texture, &srvDesc, &srv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target shader resource view, result: 0x%X.", result); + } + } + + if (bindDSV) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = formatInfo.dsvFormat; + dsvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_DSV_DIMENSION_TEXTURE2D : D3D11_DSV_DIMENSION_TEXTURE2DMS; + dsvDesc.Texture2D.MipSlice = 0; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv = NULL; + result = mDevice->CreateDepthStencilView(texture, &dsvDesc, &dsv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target depth stencil view, result: 0x%X.", result); + } + + *outRT = new TextureRenderTarget11(dsv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(dsv); + } + else if (bindRTV) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = formatInfo.rtvFormat; + rtvDesc.ViewDimension = (supportedSamples == 0) ? D3D11_RTV_DIMENSION_TEXTURE2D : D3D11_RTV_DIMENSION_TEXTURE2DMS; + rtvDesc.Texture2D.MipSlice = 0; + + ID3D11RenderTargetView *rtv = NULL; + result = mDevice->CreateRenderTargetView(texture, &rtvDesc, &rtv); + if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + SafeRelease(texture); + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target render target view, result: 0x%X.", result); + } + + if (formatInfo.dataInitializerFunction != NULL) + { + const float clearValues[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; + mDeviceContext->ClearRenderTargetView(rtv, clearValues); + } + + *outRT = new TextureRenderTarget11(rtv, texture, srv, format, width, height, 1, supportedSamples); + + SafeRelease(rtv); + } + else + { + UNREACHABLE(); + } + + SafeRelease(texture); + SafeRelease(srv); } else { - // Note: render target may be NULL for 0 sized surfaces - renderTarget = new RenderTarget11(this, swapChain11->getRenderTarget(), - swapChain11->getOffscreenTexture(), - swapChain11->getRenderTargetShaderResource(), - swapChain11->getWidth(), swapChain11->getHeight(), 1); + *outRT = new TextureRenderTarget11(reinterpret_cast(NULL), NULL, NULL, format, width, height, 1, supportedSamples); } - return renderTarget; + + return gl::Error(GL_NO_ERROR); } -RenderTarget *Renderer11::createRenderTarget(int width, int height, GLenum format, GLsizei samples) +ShaderImpl *Renderer11::createShader(const gl::Data &data, GLenum type) { - RenderTarget11 *renderTarget = new RenderTarget11(this, width, height, format, samples); - return renderTarget; -} - -ShaderImpl *Renderer11::createShader(GLenum type) -{ - return new ShaderD3D(type, this); + return new ShaderD3D(data, type, this); } ProgramImpl *Renderer11::createProgram() @@ -2322,22 +2399,23 @@ void Renderer11::releaseShaderCompiler() ShaderD3D::releaseCompiler(); } -ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers) +gl::Error Renderer11::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) { - ShaderExecutable11 *executable = NULL; - HRESULT result; - switch (type) { - case rx::SHADER_VERTEX: + case SHADER_VERTEX: { ID3D11VertexShader *vertexShader = NULL; ID3D11GeometryShader *streamOutShader = NULL; - result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); + HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result); + } if (transformFeedbackVaryings.size() > 0) { @@ -2363,99 +2441,116 @@ ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(), NULL, 0, 0, NULL, &streamOutShader); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result); + } } - if (vertexShader) - { - executable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); - } + *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader); } break; - case rx::SHADER_PIXEL: + case SHADER_PIXEL: { ID3D11PixelShader *pixelShader = NULL; - result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); + HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader); ASSERT(SUCCEEDED(result)); - - if (pixelShader) + if (FAILED(result)) { - executable = new ShaderExecutable11(function, length, pixelShader); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result); } + + *outExecutable = new ShaderExecutable11(function, length, pixelShader); } break; - case rx::SHADER_GEOMETRY: + case SHADER_GEOMETRY: { ID3D11GeometryShader *geometryShader = NULL; - result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); + HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader); ASSERT(SUCCEEDED(result)); - - if (geometryShader) + if (FAILED(result)) { - executable = new ShaderExecutable11(function, length, geometryShader); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result); } + + *outExecutable = new ShaderExecutable11(function, length, geometryShader); } break; default: UNREACHABLE(); - break; + return gl::Error(GL_INVALID_OPERATION); } - return executable; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) +gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) { const char *profileType = NULL; switch (type) { - case rx::SHADER_VERTEX: + case SHADER_VERTEX: profileType = "vs"; break; - case rx::SHADER_PIXEL: + case SHADER_PIXEL: profileType = "ps"; break; - case rx::SHADER_GEOMETRY: + case SHADER_GEOMETRY: profileType = "gs"; break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } - const char *profileVersion = NULL; + unsigned int profileMajorVersion = 0; + unsigned int profileMinorVersion = 0; + const char *profileSuffix = NULL; switch (mFeatureLevel) { case D3D_FEATURE_LEVEL_11_0: - profileVersion = "5_0"; + profileMajorVersion = 5; + profileMinorVersion = 0; break; case D3D_FEATURE_LEVEL_10_1: - profileVersion = "4_1"; + profileMajorVersion = 4; + profileMinorVersion = 1; break; case D3D_FEATURE_LEVEL_10_0: - profileVersion = "4_0"; + profileMajorVersion = 4; + profileMinorVersion = 0; break; case D3D_FEATURE_LEVEL_9_3: - profileVersion = "4_0_level_9_3"; + profileMajorVersion = 4; + profileMinorVersion = 0; + profileSuffix = "_level_9_3"; break; case D3D_FEATURE_LEVEL_9_2: - profileVersion = "4_0_level_9_2"; + profileMajorVersion = 4; + profileMinorVersion = 0; + profileSuffix = "_level_9_2"; break; case D3D_FEATURE_LEVEL_9_1: - profileVersion = "4_0_level_9_1"; + profileMajorVersion = 4; + profileMinorVersion = 0; + profileSuffix = "_level_9_1"; break; + break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } - char profile[32]; - snprintf(profile, ArraySize(profile), "%s_%s", profileType, profileVersion); + std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); + if (profileSuffix) + profile += profileSuffix; - UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0; + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; if (gl::perfActive()) { @@ -2464,44 +2559,51 @@ ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const ch #endif flags |= D3DCOMPILE_DEBUG; - - std::string sourcePath = getTempPath(); - std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); - writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); } // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. // Try the default flags first and if compilation fails, try some alternatives. - const UINT extraFlags[] = - { - flags, - flags | D3DCOMPILE_SKIP_VALIDATION, - flags | D3DCOMPILE_SKIP_OPTIMIZATION - }; + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION, "skip validation" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization")); - const static char *extraFlagNames[] = - { - "default", - "skip validation", - "skip optimization" - }; + D3D_SHADER_MACRO loopMacros[] = { {"ANGLE_ENABLE_LOOP_FLATTEN", "1"}, {0, 0} }; - int attempts = ArraySize(extraFlags); - - ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); - if (!binary) + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, loopMacros, &binary, &debugInfo); + if (error.isError()) { - return NULL; + return error; } - ShaderExecutable *executable = loadExecutable((DWORD *)binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers); - SafeRelease(binary); + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } - return executable; + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); } -rx::UniformStorage *Renderer11::createUniformStorage(size_t storageSize) +UniformStorage *Renderer11::createUniformStorage(size_t storageSize) { return new UniformStorage11(this, storageSize); } @@ -2531,9 +2633,14 @@ QueryImpl *Renderer11::createQuery(GLenum type) return new Query11(this, type); } -FenceImpl *Renderer11::createFence() +FenceNVImpl *Renderer11::createFenceNV() { - return new Fence11(this); + return new FenceNV11(this); +} + +FenceSyncImpl *Renderer11::createFenceSync() +{ + return new FenceSync11(this); } TransformFeedbackImpl* Renderer11::createTransformFeedback() @@ -2576,82 +2683,77 @@ bool Renderer11::supportsFastCopyBufferToTexture(GLenum internalFormat) const return true; } -bool Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { ASSERT(supportsFastCopyBufferToTexture(destinationFormat)); return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea); } -bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource) +gl::Error Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut) + { - ASSERT(colorbuffer != NULL); + ASSERT(colorbuffer); - RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer); - if (renderTarget) + RenderTarget11 *renderTarget = NULL; + gl::Error error = d3d11::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) { - *subresourceIndex = renderTarget->getSubresourceIndex(); - - ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView(); - if (colorBufferRTV) - { - ID3D11Resource *textureResource = NULL; - colorBufferRTV->GetResource(&textureResource); - - if (textureResource) - { - HRESULT result = textureResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)resource); - SafeRelease(textureResource); - - if (SUCCEEDED(result)) - { - return true; - } - else - { - ERR("Failed to extract the ID3D11Texture2D from the render target resource, " - "HRESULT: 0x%X.", result); - } - } - } + return error; } - return false; + ID3D11Resource *renderTargetResource = renderTarget->getTexture(); + ASSERT(renderTargetResource); + + *subresourceIndexOut = renderTarget->getSubresourceIndex(); + *texture2DOut = d3d11::DynamicCastComObject(renderTargetResource); + + if (!(*texture2DOut)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the ID3D11Texture2D from a RenderTarget"); + } + + return gl::Error(GL_NO_ERROR); } -bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) +gl::Error Renderer11::blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, + const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, + bool blitDepth, bool blitStencil, GLenum filter) { if (blitRenderTarget) { gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer(); + ASSERT(readBuffer); - if (!readBuffer) + RenderTarget *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the read buffer from the read framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } - - RenderTarget *readRenderTarget = GetAttachmentRenderTarget(readBuffer); + ASSERT(readRenderTarget); for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { if (drawTarget->isEnabledColorAttachment(colorAttachment)) { gl::FramebufferAttachment *drawBuffer = drawTarget->getColorbuffer(colorAttachment); + ASSERT(drawBuffer); - if (!drawBuffer) + RenderTarget *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the draw buffer from the draw framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(drawRenderTarget); - RenderTarget *drawRenderTarget = GetAttachmentRenderTarget(drawBuffer); - - if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, - blitRenderTarget, false, false)) + error = blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, blitRenderTarget, + false, false); + if (error.isError()) { - return false; + return error; } } } @@ -2660,78 +2762,88 @@ bool Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &read if (blitDepth || blitStencil) { gl::FramebufferAttachment *readBuffer = readTarget->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + + RenderTarget *readRenderTarget = NULL; + gl::Error error = GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + gl::FramebufferAttachment *drawBuffer = drawTarget->getDepthOrStencilbuffer(); + ASSERT(drawBuffer); - if (!readBuffer) + RenderTarget *drawRenderTarget = NULL; + error = GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) { - ERR("Failed to retrieve the read depth-stencil buffer from the read framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return error; } + ASSERT(drawRenderTarget); - if (!drawBuffer) + error = blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, false, + blitDepth, blitStencil); + if (error.isError()) { - ERR("Failed to retrieve the draw depth-stencil buffer from the draw framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); - } - - RenderTarget *readRenderTarget = GetAttachmentRenderTarget(readBuffer); - RenderTarget *drawRenderTarget = GetAttachmentRenderTarget(drawBuffer); - ASSERT(readRenderTarget && drawRenderTarget); - - if (!blitRenderbufferRect(readRect, drawRect, readRenderTarget, drawRenderTarget, filter, scissor, - false, blitDepth, blitStencil)) - { - return false; + return error; } } invalidateFramebufferSwizzles(drawTarget); - return true; + return gl::Error(GL_NO_ERROR); } -gl::Error Renderer11::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, +gl::Error Renderer11::readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) { ID3D11Texture2D *colorBufferTexture = NULL; unsigned int subresourceIndex = 0; gl::FramebufferAttachment *colorbuffer = framebuffer->getReadColorbuffer(); + ASSERT(colorbuffer); - if (colorbuffer && getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture)) + gl::Error error = getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture); + if (error.isError()) { - gl::Rectangle area; - area.x = x; - area.y = y; - area.width = width; - area.height = height; - - gl::Buffer *packBuffer = pack.pixelBuffer.get(); - if (packBuffer != NULL) - { - rx::Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation()); - PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast(pixels)); - - gl::Error error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); - if (error.isError()) - { - return error; - } - - packBuffer->getIndexRangeCache()->clear(); - } - else - { - gl::Error error = readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); - if (error.isError()) - { - return error; - } - } - - SafeRelease(colorBufferTexture); + return error; } + gl::Rectangle area; + area.x = x; + area.y = y; + area.width = width; + area.height = height; + + gl::Buffer *packBuffer = pack.pixelBuffer.get(); + if (packBuffer != NULL) + { + Buffer11 *packBufferStorage = Buffer11::makeBuffer11(packBuffer->getImplementation()); + PackPixelsParams packParams(area, format, type, outputPitch, pack, reinterpret_cast(pixels)); + + error = packBufferStorage->packPixels(colorBufferTexture, subresourceIndex, packParams); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + + packBuffer->getIndexRangeCache()->clear(); + } + else + { + error = readTextureData(colorBufferTexture, subresourceIndex, area, format, type, outputPitch, pack, pixels); + if (error.isError()) + { + SafeRelease(colorBufferTexture); + return error; + } + } + + SafeRelease(colorBufferTexture); + return gl::Error(GL_NO_ERROR); } @@ -2740,11 +2852,11 @@ Image *Renderer11::createImage() return new Image11(); } -void Renderer11::generateMipmap(Image *dest, Image *src) +gl::Error Renderer11::generateMipmap(Image *dest, Image *src) { Image11 *dest11 = Image11::makeImage11(dest); Image11 *src11 = Image11::makeImage11(src); - Image11::generateMipmap(dest11, src11); + return Image11::generateMipmap(dest11, src11); } TextureStorage *Renderer11::createTextureStorage2D(SwapChain *swapChain) @@ -2788,6 +2900,19 @@ TextureImpl *Renderer11::createTexture(GLenum target) return NULL; } +RenderbufferImpl *Renderer11::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + return renderbuffer; +} + +RenderbufferImpl *Renderer11::createRenderbuffer(SwapChain *swapChain, bool depth) +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + renderbuffer->setStorage(swapChain, depth); + return renderbuffer; +} + gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) { @@ -2882,22 +3007,25 @@ gl::Error Renderer11::readTextureData(ID3D11Texture2D *texture, unsigned int sub SafeRelease(srcTex); PackPixelsParams packParams(safeArea, format, type, outputPitch, pack, 0); - packPixels(stagingTex, packParams, pixels); + gl::Error error = packPixels(stagingTex, packParams, pixels); SafeRelease(stagingTex); - return gl::Error(GL_NO_ERROR); + return error; } -void Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) +gl::Error Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut) { D3D11_TEXTURE2D_DESC textureDesc; readTexture->GetDesc(&textureDesc); D3D11_MAPPED_SUBRESOURCE mapping; HRESULT hr = mDeviceContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &mapping); - UNUSED_ASSERTION_VARIABLE(hr); - ASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + { + ASSERT(hr == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to map internal texture for reading, result: 0x%X.", hr); + } uint8_t *source; int inputPitch; @@ -2968,24 +3096,23 @@ void Renderer11::packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams } mDeviceContext->Unmap(readTexture, 0); + + return gl::Error(GL_NO_ERROR); } -bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, - bool colorBlit, bool depthBlit, bool stencilBlit) +gl::Error Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit) { // Since blitRenderbufferRect is called for each render buffer that needs to be blitted, // it should never be the case that both color and depth/stencil need to be blitted at // at the same time. ASSERT(colorBlit != (depthBlit || stencilBlit)); - bool result = true; - RenderTarget11 *drawRenderTarget11 = RenderTarget11::makeRenderTarget11(drawRenderTarget); if (!drawRenderTarget) { - ERR("Failed to retrieve the draw render target from the draw framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal draw render target from the draw framebuffer."); } ID3D11Resource *drawTexture = drawRenderTarget11->getTexture(); @@ -2996,8 +3123,7 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R RenderTarget11 *readRenderTarget11 = RenderTarget11::makeRenderTarget11(readRenderTarget); if (!readRenderTarget) { - ERR("Failed to retrieve the read render target from the read framebuffer."); - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target from the read framebuffer."); } ID3D11Resource *readTexture = NULL; @@ -3019,7 +3145,7 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R if (FAILED(hresult)) { SafeRelease(readTexture); - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader resource view to resolve multisampled framebuffer."); } } } @@ -3036,8 +3162,7 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R { SafeRelease(readTexture); SafeRelease(readSRV); - ERR("Failed to retrieve the read render target view from the read render target."); - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to retrieve the internal read render target view from the read render target."); } gl::Extents readSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); @@ -3063,6 +3188,8 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R const gl::InternalFormat &actualFormatInfo = gl::GetInternalFormatInfo(drawRenderTarget->getActualFormat()); bool partialDSBlit = (actualFormatInfo.depthBits > 0 && depthBlit) != (actualFormatInfo.stencilBits > 0 && stencilBlit); + gl::Error result(GL_NO_ERROR); + if (readRenderTarget11->getActualFormat() == drawRenderTarget->getActualFormat() && !stretchRequired && !outOfBounds && !flipRequired && !partialDSBlit && (!(depthBlit || stencilBlit) || wholeBufferCopy)) @@ -3109,7 +3236,7 @@ bool Renderer11::blitRenderbufferRect(const gl::Rectangle &readRect, const gl::R mDeviceContext->CopySubresourceRegion(drawTexture, drawSubresource, dstX, dstY, 0, readTexture, readSubresource, pSrcBox); - result = true; + result = gl::Error(GL_NO_ERROR); } else { @@ -3190,7 +3317,8 @@ void Renderer11::invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *atta ASSERT(attachment->isTexture()); gl::Texture *texture = attachment->getTexture(); - TextureStorage *texStorage = texture->getNativeTexture(); + TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); + TextureStorage *texStorage = textureD3D->getNativeTexture(); if (texStorage) { TextureStorage11 *texStorage11 = TextureStorage11::makeTextureStorage11(texStorage); @@ -3204,7 +3332,7 @@ void Renderer11::invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *atta } } -void Renderer11::invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer) +void Renderer11::invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer) { for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++) { @@ -3248,7 +3376,7 @@ bool Renderer11::getLUID(LUID *adapterLuid) const return true; } -rx::VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +VertexConversionType Renderer11::getVertexConversionType(const gl::VertexFormat &vertexFormat) const { return d3d11::GetVertexFormatInfo(vertexFormat).conversionType; } @@ -3263,4 +3391,30 @@ void Renderer11::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureC d3d11_gl::GenerateCaps(mDevice, outCaps, outTextureCaps, outExtensions); } +Workarounds Renderer11::generateWorkarounds() const +{ + return d3d11::GenerateWorkarounds(); +} + +void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) +{ + std::vector ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + + if (currentSRVs[resourceSlot] != srv) + { + if (shaderType == gl::SAMPLER_VERTEX) + { + mDeviceContext->VSSetShaderResources(resourceSlot, 1, &srv); + } + else + { + mDeviceContext->PSSetShaderResources(resourceSlot, 1, &srv); + } + + currentSRVs[resourceSlot] = srv; + } +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h index 2a53fa1672..d44bd2fd30 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h @@ -13,12 +13,14 @@ #include "libGLESv2/angletypes.h" #include "common/mathutil.h" -#include "libGLESv2/renderer/Renderer.h" -#include "libGLESv2/renderer/d3d/HLSLCompiler.h" #include "libGLESv2/renderer/d3d/d3d11/RenderStateCache.h" #include "libGLESv2/renderer/d3d/d3d11/InputLayoutCache.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/renderer/RenderTarget.h" +#include "libEGL/AttributeMap.h" + namespace gl { class FramebufferAttachment; @@ -33,6 +35,7 @@ class StreamingIndexBufferInterface; class Blit11; class Clear11; class PixelTransfer11; +class RenderTarget11; struct PackPixelsParams; enum @@ -41,10 +44,10 @@ enum MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024 }; -class Renderer11 : public Renderer +class Renderer11 : public RendererD3D { public: - Renderer11(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); + Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes); virtual ~Renderer11(); static Renderer11 *makeRenderer11(Renderer *renderer); @@ -55,19 +58,19 @@ class Renderer11 : public Renderer virtual int generateConfigs(ConfigDesc **configDescList); virtual void deleteConfigs(ConfigDesc *configDescList); - virtual void sync(bool block); + virtual gl::Error sync(bool block); - virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); virtual gl::Error generateSwizzle(gl::Texture *texture); - virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); - virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, int stencilBackRef, bool frontFaceCCW); @@ -76,32 +79,32 @@ class Renderer11 : public Renderer bool ignoreViewport); virtual bool applyPrimitiveType(GLenum mode, GLsizei count); - virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer); + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive); - virtual gl::Error applyUniforms(const gl::ProgramBinary &programBinary); - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances); + + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + virtual void applyTransformFeedbackBuffers(const gl::State &state); virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); - virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) override; virtual void markAllStateDirty(); // lost device - void notifyDeviceLost(); - virtual bool isDeviceLost(); - virtual bool testDeviceLost(bool notify); - virtual bool testDeviceResettable(); + void notifyDeviceLost() override; + bool isDeviceLost() override; + bool testDeviceLost(bool notify) override; + bool testDeviceResettable() override; - virtual DWORD getAdapterVendor() const; - virtual std::string getRendererDescription() const; - virtual GUID getAdapterIdentifier() const; + DWORD getAdapterVendor() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; virtual unsigned int getReservedVertexUniformVectors() const; virtual unsigned int getReservedFragmentUniformVectors() const; @@ -115,47 +118,43 @@ class Renderer11 : public Renderer virtual int getMaxSwapInterval() const; // Pixel operations - virtual bool copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source); - - virtual bool copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - virtual bool copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); - virtual bool copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual bool copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) override; - virtual gl::Error readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); // RenderTarget creation - virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); + virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT); + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT); // Shader creation - virtual ShaderImpl *createShader(GLenum type); + virtual ShaderImpl *createShader(const gl::Data &data, GLenum type); virtual ProgramImpl *createProgram(); // Shader operations - virtual void releaseShaderCompiler(); - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround); + void releaseShaderCompiler() override; + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable); virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); - virtual void generateMipmap(Image *dest, Image *source); + gl::Error generateMipmap(Image *dest, Image *source) override; virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); @@ -165,6 +164,10 @@ class Renderer11 : public Renderer // Texture creation virtual TextureImpl *createTexture(GLenum target); + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth); + // Buffer creation virtual BufferImpl *createBuffer(); virtual VertexBuffer *createVertexBuffer(); @@ -175,7 +178,8 @@ class Renderer11 : public Renderer // Query and Fence creation virtual QueryImpl *createQuery(GLenum type); - virtual FenceImpl *createFence(); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); // Transform Feedback creation virtual TransformFeedbackImpl* createTransformFeedback(); @@ -183,48 +187,54 @@ class Renderer11 : public Renderer // D3D11-renderer specific methods ID3D11Device *getDevice() { return mDevice; } ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; - IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } Blit11 *getBlitter() { return mBlit; } // Buffer-to-texture and Texture-to-buffer copies virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + + gl::Error getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut); - bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource); void unapplyRenderTargets(); void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView); - void packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); + gl::Error packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams ¶ms, uint8_t *pixelsOut); virtual bool getLUID(LUID *adapterLuid) const; - virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; - private: - DISALLOW_COPY_AND_ASSIGN(Renderer11); - - virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; - - gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); - gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); - gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); - bool blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, - RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, - bool colorBlit, bool depthBlit, bool stencilBlit); + void setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv); + + private: + DISALLOW_COPY_AND_ASSIGN(Renderer11); + + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; + + gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer); + gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances); + + gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget, + RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor, + bool colorBlit, bool depthBlit, bool stencilBlit); ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource); + void unsetSRVsWithResource(gl::SamplerType shaderType, const ID3D11Resource *resource); static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel); - static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer); + static void invalidateFramebufferSwizzles(const gl::Framebuffer *framebuffer); HMODULE mD3d11Module; HMODULE mDxgiModule; EGLNativeDisplayType mDc; - EGLint mRequestedDisplay; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mDriverType; HLSLCompiler mCompiler; @@ -243,7 +253,7 @@ class Renderer11 : public Renderer unsigned int mAppliedStencilbufferSerial; bool mDepthStencilInitialized; bool mRenderTargetDescInitialized; - rx::RenderTarget::Desc mRenderTargetDesc; + RenderTarget::Desc mRenderTargetDesc; // Currently applied sampler states std::vector mForceSetVertexSamplerStates; @@ -292,8 +302,14 @@ class Renderer11 : public Renderer unsigned int mAppliedIBOffset; // Currently applied transform feedback buffers - ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; - GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; + ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers + // in use for streamout + GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified + // buffer offsets to transform feedback + // buffers + UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the D3D buffer offsets, + // which may differ from GLs, due + // to different append behavior // Currently applied shaders ID3D11VertexShader *mAppliedVertexShader; @@ -339,7 +355,7 @@ class Renderer11 : public Renderer IDXGIAdapter *mDxgiAdapter; DXGI_ADAPTER_DESC mAdapterDescription; char mDescription[128]; - IDXGIFactory *mDxgiFactory; + DXGIFactory *mDxgiFactory; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp index 4b29be055d..52c8a81633 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp @@ -6,7 +6,6 @@ // SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. -#include "common/platform.h" #include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" @@ -16,12 +15,16 @@ #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" +#include "common/features.h" +#include "common/NativeWindow.h" + namespace rx { -SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, +SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) + : mRenderer(renderer), + SwapChain(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat) { mSwapChain = NULL; mBackBufferTexture = NULL; @@ -39,8 +42,8 @@ SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDL mPassThroughPS = NULL; mWidth = -1; mHeight = -1; - mViewportWidth = -1; - mViewportHeight = -1; + mRotateL = false; + mRotateR = false; mSwapInterval = 0; mAppCreatedShareHandle = mShareHandle != NULL; mPassThroughResourcesInit = false; @@ -91,11 +94,11 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei ASSERT(device != NULL); // D3D11 does not allow zero size textures - ASSERT(backbufferWidth >= 1); - ASSERT(backbufferHeight >= 1); + ASSERT(backbufferWidth != 0); + ASSERT(backbufferHeight != 0); // Preserve the render target content -#if !defined(ANGLE_PLATFORM_WINRT) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; if (previousOffscreenTexture) { @@ -137,8 +140,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; mOffscreenTexture->GetDesc(&offscreenTextureDesc); - if (offscreenTextureDesc.Width != (UINT)backbufferWidth || - offscreenTextureDesc.Height != (UINT)backbufferHeight || + if (offscreenTextureDesc.Width != UINT(abs(backbufferWidth)) || + offscreenTextureDesc.Height != UINT(abs(backbufferHeight)) || offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || offscreenTextureDesc.MipLevels != 1 || offscreenTextureDesc.ArraySize != 1) @@ -150,11 +153,11 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } else { - const bool useSharedResource = !mWindow && mRenderer->getShareHandleSupport(); + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; - offscreenTextureDesc.Width = backbufferWidth; - offscreenTextureDesc.Height = backbufferHeight; + offscreenTextureDesc.Width = abs(backbufferWidth); + offscreenTextureDesc.Height = abs(backbufferHeight); offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; offscreenTextureDesc.MipLevels = 1; offscreenTextureDesc.ArraySize = 1; @@ -234,8 +237,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei if (mDepthBufferFormat != GL_NONE) { D3D11_TEXTURE2D_DESC depthStencilTextureDesc; - depthStencilTextureDesc.Width = backbufferWidth; - depthStencilTextureDesc.Height = backbufferHeight; + depthStencilTextureDesc.Width = abs(backbufferWidth); + depthStencilTextureDesc.Height = abs(backbufferHeight); depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; depthStencilTextureDesc.MipLevels = 1; depthStencilTextureDesc.ArraySize = 1; @@ -286,12 +289,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei mWidth = backbufferWidth; mHeight = backbufferHeight; -#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP - mViewportWidth = backbufferWidth; - mViewportHeight = backbufferHeight; -#endif -#if !defined(ANGLE_PLATFORM_WINRT) +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) if (previousOffscreenTexture != NULL) { D3D11_BOX sourceBox = {0}; @@ -310,7 +309,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei if (mSwapChain) { - swapRect(0, 0, mWidth, mHeight, SWAP_NORMAL); + swapRect(0, 0, mWidth, mHeight); } } #endif @@ -327,8 +326,16 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) return EGL_BAD_ACCESS; } + // Windows Phone works around the rotation limitation by using negative values for the swap chain size +#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + mRotateL = backbufferWidth < 0; // Landscape/InvertedLandscape + mRotateR = backbufferHeight < 0; // InvertedPortrait/InvertedLandscape + backbufferWidth = abs(backbufferWidth); + backbufferHeight = abs(backbufferHeight); +#endif + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains - if (backbufferWidth < 1 || backbufferHeight < 1) + if (backbufferWidth == 0 || backbufferHeight == 0) { return EGL_SUCCESS; } @@ -336,19 +343,15 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) // Can only call resize if we have already created our swap buffer and resources ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // The swap chain is not directly resized on Windows Phone SafeRelease(mBackBufferTexture); SafeRelease(mBackBufferRTView); // Resize swap chain - HRESULT result; -#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP // Windows phone swap chain is never resized, only the texture is -#if !defined(ANGLE_PLATFORM_WINRT) - const int bufferCount = 1; -#else - const int bufferCount = 2; -#endif + DXGI_SWAP_CHAIN_DESC desc; + mSwapChain->GetDesc(&desc); const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); - result = mSwapChain->ResizeBuffers(bufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); + HRESULT result = mSwapChain->ResizeBuffers(desc.BufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); if (FAILED(result)) { @@ -364,7 +367,6 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) return EGL_BAD_ALLOC; } } -#endif result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); ASSERT(SUCCEEDED(result)); @@ -379,6 +381,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) { d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); } +#endif return resetOffscreenTexture(backbufferWidth, backbufferHeight); } @@ -412,62 +415,14 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap return EGL_SUCCESS; } - if (mWindow) + if (mNativeWindow.getNativeWindow()) { const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); - IDXGIFactory *factory = mRenderer->getDxgiFactory(); + HRESULT result = mNativeWindow.createSwapChain(device, mRenderer->getDxgiFactory(), + backbufferFormatInfo.texFormat, + backbufferWidth, backbufferHeight, &mSwapChain); -#if !defined(ANGLE_PLATFORM_WINRT) - DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; - swapChainDesc.BufferDesc.Width = backbufferWidth; - swapChainDesc.BufferDesc.Height = backbufferHeight; - swapChainDesc.BufferDesc.RefreshRate.Numerator = 0; - swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; - swapChainDesc.BufferDesc.Format = backbufferFormatInfo.texFormat; - swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = 1; - swapChainDesc.OutputWindow = mWindow; - swapChainDesc.Windowed = TRUE; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - swapChainDesc.Flags = 0; - - HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); -#else - IDXGIFactory2 *factory2; - HRESULT result = factory->QueryInterface(IID_PPV_ARGS(&factory2)); - ASSERT(SUCCEEDED(result)); - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; - swapChainDesc.Width = 0; - swapChainDesc.Height = 0; - swapChainDesc.Format = backbufferFormatInfo.texFormat; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.Stereo = FALSE; - swapChainDesc.Flags = 0; -#if WINAPI_FAMILY==WINAPI_FAMILY_PC_APP - swapChainDesc.Scaling = DXGI_SCALING_NONE; - swapChainDesc.BufferCount = 2; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; -#elif WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP - swapChainDesc.BufferCount = 1; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; -#endif - - IDXGISwapChain1 *swapChain; - result = factory2->CreateSwapChainForCoreWindow(device, mWindow, &swapChainDesc, NULL, &swapChain); - mSwapChain = swapChain; - HRESULT hr = swapChain->GetDesc1(&swapChainDesc); - ASSERT(SUCCEEDED(hr)); - mViewportWidth = swapChainDesc.Width; - mViewportHeight = swapChainDesc.Height; -#endif if (FAILED(result)) { ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); @@ -537,7 +492,7 @@ void SwapChain11::initPassThroughResources() samplerDesc.BorderColor[2] = 0.0f; samplerDesc.BorderColor[3] = 0.0f; samplerDesc.MinLOD = 0; - samplerDesc.MaxLOD = FLT_MAX; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); ASSERT(SUCCEEDED(result)); @@ -563,7 +518,7 @@ void SwapChain11::initPassThroughResources() } // parameters should be validated/clamped by caller -EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) +EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { if (!mSwapChain) { @@ -573,16 +528,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EG ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // Set vertices - D3D11_MAPPED_SUBRESOURCE mappedResource; - HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); - if (FAILED(result)) - { - return EGL_BAD_ACCESS; - } - - d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); - // Create a quad in homogeneous coordinates float x1 = (x / float(mWidth)) * 2.0f - 1.0f; float y1 = (y / float(mHeight)) * 2.0f - 1.0f; @@ -594,8 +539,18 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EG float u2 = (x + width) / float(mWidth); float v2 = (y + height) / float(mHeight); - const int rotateL = flags & SWAP_ROTATE_90; - const int rotateR = flags & SWAP_ROTATE_270; + const bool rotateL = mRotateL; + const bool rotateR = mRotateR; + + // Set vertices + D3D11_MAPPED_SUBRESOURCE mappedResource; + HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) + { + return EGL_BAD_ACCESS; + } + + d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); @@ -628,22 +583,23 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EG // Set the viewport D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = mViewportWidth; - viewport.Height = mViewportHeight; + viewport.TopLeftX = 0.0f; + viewport.TopLeftY = 0.0f; + const bool invertViewport = (mRotateL || mRotateR) && !(mRotateL && mRotateR); + viewport.Width = FLOAT(invertViewport ? mHeight : mWidth); + viewport.Height = FLOAT(invertViewport ? mWidth : mHeight); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; deviceContext->RSSetViewports(1, &viewport); // Apply textures - deviceContext->PSSetShaderResources(0, 1, &mOffscreenSRView); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, mOffscreenSRView); deviceContext->PSSetSamplers(0, 1, &mPassThroughSampler); // Draw deviceContext->Draw(4, 0); -#ifdef ANGLE_FORCE_VSYNC_OFF +#if ANGLE_VSYNC == ANGLE_DISABLED result = mSwapChain->Present(0, 0); #else result = mSwapChain->Present(mSwapInterval, 0); @@ -667,8 +623,7 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EG } // Unbind - static ID3D11ShaderResourceView *const nullSRV = NULL; - deviceContext->PSSetShaderResources(0, 1, &nullSRV); + mRenderer->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); mRenderer->unapplyRenderTargets(); mRenderer->markAllStateDirty(); @@ -708,8 +663,8 @@ ID3D11Texture2D *SwapChain11::getDepthStencilTexture() SwapChain11 *SwapChain11::makeSwapChain11(SwapChain *swapChain) { - ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain11*, swapChain)); - return static_cast(swapChain); + ASSERT(HAS_DYNAMIC_TYPE(SwapChain11*, swapChain)); + return static_cast(swapChain); } void SwapChain11::recreate() diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h index b30b78568a..77509edcd3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h @@ -19,13 +19,13 @@ class Renderer11; class SwapChain11 : public SwapChain { public: - SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, + SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); virtual ~SwapChain11(); EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); virtual void recreate(); virtual ID3D11Texture2D *getOffscreenTexture(); @@ -52,13 +52,13 @@ class SwapChain11 : public SwapChain Renderer11 *mRenderer; EGLint mHeight; EGLint mWidth; - EGLint mViewportWidth; - EGLint mViewportHeight; + bool mRotateL; + bool mRotateR; bool mAppCreatedShareHandle; unsigned int mSwapInterval; bool mPassThroughResourcesInit; - IDXGISwapChain *mSwapChain; + DXGISwapChain *mSwapChain; ID3D11Texture2D *mBackBufferTexture; ID3D11RenderTargetView *mBackBufferRTView; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp index 91e7147da6..74af27e8b3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp @@ -8,6 +8,9 @@ // classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 texture. #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h" + +#include + #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h" #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" #include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" @@ -15,6 +18,7 @@ #include "libGLESv2/renderer/d3d/d3d11/Blit11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/Image11.h" +#include "libGLESv2/renderer/d3d/MemoryBuffer.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" #include "libGLESv2/main.h" #include "libGLESv2/ImageIndex.h" @@ -52,46 +56,16 @@ TextureStorage11::SRVKey::SRVKey(int baseLevel, int mipLevels, bool swizzle) { } -bool TextureStorage11::SRVKey::operator==(const SRVKey &rhs) const +bool TextureStorage11::SRVKey::operator<(const SRVKey &rhs) const { - return baseLevel == rhs.baseLevel && - mipLevels == rhs.mipLevels && - swizzle == rhs.swizzle; + return std::tie(baseLevel, mipLevels, swizzle) < std::tie(rhs.baseLevel, rhs.mipLevels, rhs.swizzle); } -TextureStorage11::SRVCache::~SRVCache() -{ - for (size_t i = 0; i < cache.size(); i++) - { - SafeRelease(cache[i].srv); - } -} - -ID3D11ShaderResourceView *TextureStorage11::SRVCache::find(const SRVKey &key) const -{ - for (size_t i = 0; i < cache.size(); i++) - { - if (cache[i].key == key) - { - return cache[i].srv; - } - } - - return NULL; -} - -ID3D11ShaderResourceView *TextureStorage11::SRVCache::add(const SRVKey &key, ID3D11ShaderResourceView *srv) -{ - SRVPair pair = {key, srv}; - cache.push_back(pair); - - return srv; -} - -TextureStorage11::TextureStorage11(Renderer *renderer, UINT bindFlags) +TextureStorage11::TextureStorage11(Renderer11 *renderer, UINT bindFlags) : mBindFlags(bindFlags), mTopLevel(0), mMipLevels(0), + mInternalFormat(GL_NONE), mTextureFormat(DXGI_FORMAT_UNKNOWN), mShaderResourceFormat(DXGI_FORMAT_UNKNOWN), mRenderTargetFormat(DXGI_FORMAT_UNKNOWN), @@ -114,6 +88,12 @@ TextureStorage11::~TextureStorage11() { SafeRelease(mLevelSRVs[level]); } + + for (SRVCache::iterator i = mSrvCache.begin(); i != mSrvCache.end(); i++) + { + SafeRelease(i->second); + } + mSrvCache.clear(); } TextureStorage11 *TextureStorage11::makeTextureStorage11(TextureStorage *storage) @@ -183,17 +163,16 @@ int TextureStorage11::getLevelDepth(int mipLevel) const return std::max(static_cast(mTextureDepth) >> mipLevel, 1); } -UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const +UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const { - UINT index = 0; - if (getResource()) - { - index = D3D11CalcSubresource(mipLevel, layerTarget, mMipLevels); - } - return index; + UINT mipSlice = static_cast(index.mipIndex + mTopLevel); + UINT arraySlice = static_cast(index.hasLayer() ? index.layerIndex : 0); + UINT subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels); + ASSERT(subresource != std::numeric_limits::max()); + return subresource; } -ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &samplerState) +gl::Error TextureStorage11::getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV) { bool swizzleRequired = samplerState.swizzleRequired(); bool mipmapping = gl::IsMipmapFiltered(samplerState); @@ -206,38 +185,71 @@ ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &sampl { verifySwizzleExists(samplerState.swizzleRed, samplerState.swizzleGreen, samplerState.swizzleBlue, samplerState.swizzleAlpha); } - + SRVKey key(samplerState.baseLevel, mipLevels, swizzleRequired); - ID3D11ShaderResourceView *srv = srvCache.find(key); - - if(srv) + SRVCache::const_iterator iter = mSrvCache.find(key); + if (iter != mSrvCache.end()) { - return srv; - } - - DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); - ID3D11Resource *texture = swizzleRequired ? getSwizzleTexture() : getResource(); - - srv = createSRV(samplerState.baseLevel, mipLevels, format, texture); - - return srvCache.add(key, srv); -} - -ID3D11ShaderResourceView *TextureStorage11::getSRVLevel(int mipLevel) -{ - if (mipLevel >= 0 && mipLevel < getLevelCount()) - { - if (!mLevelSRVs[mipLevel]) - { - mLevelSRVs[mipLevel] = createSRV(mipLevel, 1, mShaderResourceFormat, getResource()); - } - - return mLevelSRVs[mipLevel]; + *outSRV = iter->second; } else { - return NULL; + ID3D11Resource *texture = NULL; + if (swizzleRequired) + { + gl::Error error = getSwizzleTexture(&texture); + if (error.isError()) + { + return error; + } + } + else + { + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } + } + + ID3D11ShaderResourceView *srv = NULL; + DXGI_FORMAT format = (swizzleRequired ? mSwizzleShaderResourceFormat : mShaderResourceFormat); + gl::Error error = createSRV(samplerState.baseLevel, mipLevels, format, texture, &srv); + if (error.isError()) + { + return error; + } + + mSrvCache.insert(std::make_pair(key, srv)); + *outSRV = srv; } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV) +{ + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + if (!mLevelSRVs[mipLevel]) + { + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + + error = createSRV(mipLevel, 1, mShaderResourceFormat, resource, &mLevelSRVs[mipLevel]); + if (error.isError()) + { + return error; + } + } + + *outSRV = mLevelSRVs[mipLevel]; + + return gl::Error(GL_NO_ERROR); } gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) @@ -249,14 +261,25 @@ gl::Error TextureStorage11::generateSwizzles(GLenum swizzleRed, GLenum swizzleGr if (mSwizzleCache[level] != swizzleTarget) { // Need to re-render the swizzle for this level - ID3D11ShaderResourceView *sourceSRV = getSRVLevel(level); - ID3D11RenderTargetView *destRTV = getSwizzleRenderTarget(level); + ID3D11ShaderResourceView *sourceSRV = NULL; + gl::Error error = getSRVLevel(level, &sourceSRV); + if (error.isError()) + { + return error; + } + + ID3D11RenderTargetView *destRTV = NULL; + error = getSwizzleRenderTarget(level, &destRTV); + if (error.isError()) + { + return error; + } gl::Extents size(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); Blit11 *blitter = mRenderer->getBlitter(); - gl::Error error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); + error = blitter->swizzleTexture(sourceSRV, destRTV, size, swizzleRed, swizzleGreen, swizzleBlue, swizzleAlpha); if (error.isError()) { return error; @@ -287,104 +310,120 @@ void TextureStorage11::invalidateSwizzleCache() } } -bool TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, - int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth) +gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area) { - if (srcTexture) + ASSERT(srcTexture); + + GLint level = index.mipIndex; + + invalidateSwizzleCacheLevel(level); + + gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); + + bool fullCopy = copyArea.x == 0 && + copyArea.y == 0 && + copyArea.z == 0 && + copyArea.width == texSize.width && + copyArea.height == texSize.height && + copyArea.depth == texSize.depth; + + ID3D11Resource *dstTexture = NULL; + gl::Error error = getResource(&dstTexture); + if (error.isError()) { - invalidateSwizzleCacheLevel(level); - - gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level)); - gl::Box copyArea(xoffset, yoffset, zoffset, width, height, depth); - - bool fullCopy = copyArea.x == 0 && - copyArea.y == 0 && - copyArea.z == 0 && - copyArea.width == texSize.width && - copyArea.height == texSize.height && - copyArea.depth == texSize.depth; - - ID3D11Resource *dstTexture = getResource(); - unsigned int dstSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); - - ASSERT(dstTexture); - - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) - { - // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead - Blit11 *blitter = mRenderer->getBlitter(); - - return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, - dstTexture, dstSubresource, copyArea, texSize, - NULL); - } - else - { - const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); - - D3D11_BOX srcBox; - srcBox.left = copyArea.x; - srcBox.top = copyArea.y; - srcBox.right = copyArea.x + roundUp((unsigned int)width, dxgiFormatInfo.blockWidth); - srcBox.bottom = copyArea.y + roundUp((unsigned int)height, dxgiFormatInfo.blockHeight); - srcBox.front = copyArea.z; - srcBox.back = copyArea.z + copyArea.depth; - - ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - - context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, - srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); - return true; - } + return error; } - return false; -} + unsigned int dstSubresource = getSubresourceIndex(index); -bool TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, - int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth) -{ - if (dstTexture) + ASSERT(dstTexture); + + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0)) { - ID3D11Resource *srcTexture = getResource(); - unsigned int srcSubresource = getSubresourceIndex(level + mTopLevel, layerTarget); + // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead + Blit11 *blitter = mRenderer->getBlitter(); - ASSERT(srcTexture); + return blitter->copyDepthStencil(srcTexture, sourceSubresource, copyArea, texSize, + dstTexture, dstSubresource, copyArea, texSize, + NULL); + } + else + { + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat); + + D3D11_BOX srcBox; + srcBox.left = copyArea.x; + srcBox.top = copyArea.y; + srcBox.right = copyArea.x + roundUp(static_cast(copyArea.width), dxgiFormatInfo.blockWidth); + srcBox.bottom = copyArea.y + roundUp(static_cast(copyArea.height), dxgiFormatInfo.blockHeight); + srcBox.front = copyArea.z; + srcBox.back = copyArea.z + copyArea.depth; ID3D11DeviceContext *context = mRenderer->getDeviceContext(); - context->CopySubresourceRegion(dstTexture, dstSubresource, xoffset, yoffset, zoffset, - srcTexture, srcSubresource, NULL); - return true; + context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z, + srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox); + return gl::Error(GL_NO_ERROR); } - - return false; } -void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest) +gl::Error TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion) { - if (source && dest) + ASSERT(dstTexture); + + ID3D11Resource *srcTexture = NULL; + gl::Error error = getResource(&srcTexture); + if (error.isError()) { - ID3D11ShaderResourceView *sourceSRV = source->getShaderResourceView(); - ID3D11RenderTargetView *destRTV = dest->getRenderTargetView(); - - if (sourceSRV && destRTV) - { - gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); - gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); - - gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); - gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); - - Blit11 *blitter = mRenderer->getBlitter(); - - blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, - gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR); - } + return error; } + + ASSERT(srcTexture); + + unsigned int srcSubresource = getSubresourceIndex(index); + + ID3D11DeviceContext *context = mRenderer->getDeviceContext(); + context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z, + srcTexture, srcSubresource, NULL); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + ASSERT(sourceIndex.layerIndex == destIndex.layerIndex); + + invalidateSwizzleCacheLevel(destIndex.mipIndex); + + RenderTarget *source = NULL; + gl::Error error = getRenderTarget(sourceIndex, &source); + if (error.isError()) + { + return error; + } + + RenderTarget *dest = NULL; + error = getRenderTarget(destIndex, &dest); + if (error.isError()) + { + return error; + } + + ID3D11ShaderResourceView *sourceSRV = RenderTarget11::makeRenderTarget11(source)->getShaderResourceView(); + ID3D11RenderTargetView *destRTV = RenderTarget11::makeRenderTarget11(dest)->getRenderTargetView(); + + gl::Box sourceArea(0, 0, 0, source->getWidth(), source->getHeight(), source->getDepth()); + gl::Extents sourceSize(source->getWidth(), source->getHeight(), source->getDepth()); + + gl::Box destArea(0, 0, 0, dest->getWidth(), dest->getHeight(), dest->getDepth()); + gl::Extents destSize(dest->getWidth(), dest->getHeight(), dest->getDepth()); + + Blit11 *blitter = mRenderer->getBlitter(); + return blitter->copyTexture(sourceSRV, sourceArea, sourceSize, destRTV, destArea, destSize, NULL, + gl::GetInternalFormatInfo(source->getInternalFormat()).format, GL_LINEAR); } void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha) @@ -396,7 +435,112 @@ void TextureStorage11::verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGree } } -TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain) +gl::Error TextureStorage11::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + ID3D11Resource *sourceResouce = NULL; + gl::Error error = getResource(&sourceResouce); + if (error.isError()) + { + return error; + } + + TextureStorage11 *dest11 = TextureStorage11::makeTextureStorage11(destStorage); + ID3D11Resource *destResource = NULL; + error = dest11->getResource(&destResource); + if (error.isError()) + { + return error; + } + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + immediateContext->CopyResource(destResource, sourceResouce); + + dest11->invalidateSwizzleCache(); + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage11::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + ID3D11Resource *resource = NULL; + gl::Error error = getResource(&resource); + if (error.isError()) + { + return error; + } + ASSERT(resource); + + UINT destSubresource = getSubresourceIndex(index); + + const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(image->getInternalFormat()); + + bool fullUpdate = (destBox == NULL || *destBox == gl::Box(0, 0, 0, mTextureWidth, mTextureHeight, mTextureDepth)); + ASSERT(internalFormatInfo.depthBits == 0 || fullUpdate); + + // TODO(jmadill): Handle compressed formats + // Compressed formats have different load syntax, so we'll have to handle them with slightly + // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData + // with compressed formats in the calling logic. + ASSERT(!internalFormatInfo.compressed); + + int width = destBox ? destBox->width : static_cast(image->getWidth()); + int height = destBox ? destBox->height : static_cast(image->getHeight()); + int depth = destBox ? destBox->depth : static_cast(image->getDepth()); + UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, width, unpack.alignment); + UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, width, height, unpack.alignment); + + const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(image->getInternalFormat()); + const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat); + + size_t outputPixelSize = dxgiFormatInfo.pixelBytes; + + UINT bufferRowPitch = outputPixelSize * width; + UINT bufferDepthPitch = bufferRowPitch * height; + + MemoryBuffer conversionBuffer; + if (!conversionBuffer.resize(bufferDepthPitch * depth)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer."); + } + + // TODO: fast path + LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type); + loadFunction(width, height, depth, + pixelData, srcRowPitch, srcDepthPitch, + conversionBuffer.data(), bufferRowPitch, bufferDepthPitch); + + ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext(); + + if (!fullUpdate) + { + ASSERT(destBox); + + D3D11_BOX destD3DBox; + destD3DBox.left = destBox->x; + destD3DBox.right = destBox->x + destBox->width; + destD3DBox.top = destBox->y; + destD3DBox.bottom = destBox->y + destBox->height; + destD3DBox.front = 0; + destD3DBox.back = 1; + + immediateContext->UpdateSubresource(resource, destSubresource, + &destD3DBox, conversionBuffer.data(), + bufferRowPitch, bufferDepthPitch); + } + else + { + immediateContext->UpdateSubresource(resource, destSubresource, + NULL, conversionBuffer.data(), + bufferRowPitch, bufferDepthPitch); + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain) : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), mTexture(swapchain->getOffscreenTexture()), mSwizzleTexture(NULL) @@ -418,6 +562,8 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapch mTextureHeight = texDesc.Height; mTextureDepth = 1; + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + ID3D11ShaderResourceView *srv = swapchain->getRenderTargetShaderResource(); D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srv->GetDesc(&srvDesc); @@ -439,7 +585,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapch initializeSerials(1, 1); } -TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) +TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)), mTexture(NULL), mSwizzleTexture(NULL) @@ -451,6 +597,8 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform mSwizzleRenderTargets[i] = NULL; } + mInternalFormat = internalformat; + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); mTextureFormat = formatInfo.texFormat; mShaderResourceFormat = formatInfo.srvFormat; @@ -460,51 +608,11 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // if the width or height is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (width > 0 && height > 0) - { - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; // Compressed texture size constraints? - desc.Height = height; - desc.MipLevels = desc.MipLevels = mRenderer->isLevel9() ? 1 : ((levels > 0) ? (mTopLevel + levels) : 0); - desc.ArraySize = 1; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - gl::error(GL_OUT_OF_MEMORY); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - mTextureDepth = 1; - } - } + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = 1; initializeSerials(getLevelCount(), 1); } @@ -521,7 +629,11 @@ TextureStorage11_2D::~TextureStorage11_2D() if (imageAssociationCorrect) { // We must let the Images recover their data before we delete it from the TextureStorage. - mAssociatedImages[i]->recoverFromAssociatedStorage(); + gl::Error error = mAssociatedImages[i]->recoverFromAssociatedStorage(); + if (error.isError()) + { + // TODO: Find a way to report this back to the context + } } } } @@ -542,8 +654,10 @@ TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage return static_cast(storage); } -void TextureStorage11_2D::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -552,8 +666,10 @@ void TextureStorage11_2D::associateImage(Image11* image, int level, int layerTar } } -bool TextureStorage11_2D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // This validation check should never return false. It means the Image/TextureStorage association is broken. @@ -566,8 +682,10 @@ bool TextureStorage11_2D::isAssociatedImageValid(int level, int layerTarget, Ima } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2D::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -582,8 +700,10 @@ void TextureStorage11_2D::disassociateImage(int level, int layerTarget, Image11* } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_2D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +gl::Error TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -599,137 +719,168 @@ void TextureStorage11_2D::releaseAssociatedImage(int level, int layerTarget, Ima { // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to NULL too. - mAssociatedImages[level]->recoverFromAssociatedStorage(); + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } } } } + + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *TextureStorage11_2D::getResource() const +gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) { - return mTexture; + // if the width or height is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; + desc.MipLevels = mRenderer->isLevel9() ? 1 : mMipLevels; + desc.ArraySize = 1; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); } -RenderTarget *TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureStorage11_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { ASSERT(!index.hasLayer()); int level = index.mipIndex; + ASSERT(level >= 0 && level < getLevelCount()); - if (level >= 0 && level < getLevelCount()) + if (!mRenderTarget[level]) { - if (!mRenderTarget[level]) + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) { - ID3D11ShaderResourceView *srv = getSRVLevel(level); - if (!srv) - { - return NULL; - } - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + level; - - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mRenderTarget[level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mTopLevel + level; - dsvDesc.Flags = 0; - - ID3D11DepthStencilView *dsv; - HRESULT result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mRenderTarget[level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(dsv); - } - else - { - UNREACHABLE(); - } + return error; } - return mRenderTarget[level]; - } - else - { - return NULL; + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(level, &srv); + if (error.isError()) + { + return error; + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + level; + + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mTopLevel + level; + dsvDesc.Flags = 0; + + ID3D11DepthStencilView *dsv; + HRESULT result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY,"Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + } + else + { + UNREACHABLE(); + } } + + ASSERT(outRT); + *outRT = mRenderTarget[level]; + return gl::Error(GL_NO_ERROR); } -ID3D11ShaderResourceView *TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const { + ASSERT(outSRV); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; - srvDesc.Texture2D.MipLevels = mipLevels; - - ID3D11ShaderResourceView *SRV = NULL; + srvDesc.Texture2D.MipLevels = mRenderer->isLevel9() ? -1 : mipLevels; ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); - return SRV; + return gl::Error(GL_NO_ERROR); } -void TextureStorage11_2D::generateMipmaps() +gl::Error TextureStorage11_2D::getSwizzleTexture(ID3D11Resource **outTexture) { - // Base level must already be defined + ASSERT(outTexture); - for (int level = 1; level < getLevelCount(); level++) - { - invalidateSwizzleCacheLevel(level); - - gl::ImageIndex srcIndex = gl::ImageIndex::Make2D(level - 1); - gl::ImageIndex destIndex = gl::ImageIndex::Make2D(level); - - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(srcIndex)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(destIndex)); - - generateMipmapLayer(source, dest); - } -} - -ID3D11Resource *TextureStorage11_2D::getSwizzleTexture() -{ if (!mSwizzleTexture) { ID3D11Device *device = mRenderer->getDevice(); @@ -749,52 +900,52 @@ ID3D11Resource *TextureStorage11_2D::getSwizzleTexture() HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); } - return mSwizzleTexture; + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11RenderTargetView *TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel) +gl::Error TextureStorage11_2D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) { - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) { - if (!mSwizzleRenderTargets[mipLevel]) + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) { - ID3D11Resource *swizzleTexture = getSwizzleTexture(); - if (!swizzleTexture) - { - return NULL; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); + return error; } - return mSwizzleRenderTargets[mipLevel]; - } - else - { - return NULL; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mTopLevel + mipLevel; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); } -TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) +TextureStorage11_Cube::TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels) : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) { mTexture = NULL; @@ -803,13 +954,15 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { mSwizzleRenderTargets[level] = NULL; - for (unsigned int face = 0; face < 6; face++) + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) { mAssociatedImages[face][level] = NULL; mRenderTarget[face][level] = NULL; } } + mInternalFormat = internalformat; + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); mTextureFormat = formatInfo.texFormat; mShaderResourceFormat = formatInfo.srvFormat; @@ -819,56 +972,23 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // if the size is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (size > 0) - { - // adjust size if needed for compressed textures - int height = size; - d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); + // adjust size if needed for compressed textures + int height = size; + d3d11::MakeValidSize(false, mTextureFormat, &size, &height, &mTopLevel); - ID3D11Device *device = mRenderer->getDevice(); + mMipLevels = mTopLevel + levels; + mTextureWidth = size; + mTextureHeight = size; + mTextureDepth = 1; - D3D11_TEXTURE2D_DESC desc; - desc.Width = size; - desc.Height = size; - desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); - desc.ArraySize = 6; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - mTextureDepth = 1; - } - } - - initializeSerials(getLevelCount() * 6, 6); + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); } - TextureStorage11_Cube::~TextureStorage11_Cube() { for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { - for (unsigned int face = 0; face < 6; face++) + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) { if (mAssociatedImages[face][level] != NULL) { @@ -890,7 +1010,7 @@ TextureStorage11_Cube::~TextureStorage11_Cube() for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++) { SafeRelease(mSwizzleRenderTargets[level]); - for (unsigned int face = 0; face < 6; face++) + for (unsigned int face = 0; face < CUBE_FACE_COUNT; face++) { SafeDelete(mRenderTarget[face][level]); } @@ -903,25 +1023,31 @@ TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureS return static_cast(storage); } -void TextureStorage11_Cube::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < 6); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - if (0 <= layerTarget && layerTarget < 6) + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) { mAssociatedImages[layerTarget][level] = image; } } } -bool TextureStorage11_Cube::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - if (0 <= layerTarget && layerTarget < 6) + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) { // This validation check should never return false. It means the Image/TextureStorage association is broken. bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage); @@ -934,14 +1060,17 @@ bool TextureStorage11_Cube::isAssociatedImageValid(int level, int layerTarget, I } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_Cube::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < 6); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { - if (0 <= layerTarget && layerTarget < 6) + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) { ASSERT(mAssociatedImages[layerTarget][level] == expectedImage); @@ -954,14 +1083,17 @@ void TextureStorage11_Cube::disassociateImage(int level, int layerTarget, Image1 } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_Cube::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +gl::Error TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); - ASSERT(0 <= layerTarget && layerTarget < 6); + ASSERT(0 <= layerTarget && layerTarget < CUBE_FACE_COUNT); if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)) { - if (0 <= layerTarget && layerTarget < 6) + if (0 <= layerTarget && layerTarget < CUBE_FACE_COUNT) { // No need to let the old Image recover its data, if it is also the incoming Image. if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage) @@ -974,114 +1106,165 @@ void TextureStorage11_Cube::releaseAssociatedImage(int level, int layerTarget, I { // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to NULL too. - mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); + gl::Error error = mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } } } } } + + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *TextureStorage11_Cube::getResource() const +gl::Error TextureStorage11_Cube::getResource(ID3D11Resource **outResource) { - return mTexture; + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = CUBE_FACE_COUNT; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); } -RenderTarget *TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureStorage11_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { int faceIndex = index.layerIndex; int level = index.mipIndex; - if (level >= 0 && level < getLevelCount()) + ASSERT(level >= 0 && level < getLevelCount()); + ASSERT(faceIndex >= 0 && faceIndex < CUBE_FACE_COUNT); + + if (!mRenderTarget[faceIndex][level]) { - if (!mRenderTarget[faceIndex][level]) + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; - - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = faceIndex; - srvDesc.Texture2DArray.ArraySize = 1; - - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; - rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); - SafeRelease(srv); - } - else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; - dsvDesc.Format = mDepthStencilFormat; - dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; - dsvDesc.Flags = 0; - dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; - dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; - dsvDesc.Texture2DArray.ArraySize = 1; - - ID3D11DepthStencilView *dsv; - result = device->CreateDepthStencilView(mTexture, &dsvDesc, &dsv); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mRenderTarget[faceIndex][level] = new RenderTarget11(mRenderer, dsv, mTexture, srv, getLevelWidth(level), getLevelHeight(level), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(dsv); - SafeRelease(srv); - } - else - { - UNREACHABLE(); - } + return error; } - return mRenderTarget[faceIndex][level]; - } - else - { - return NULL; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; // Will be used with Texture2D sampler, not TextureCube + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + level; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = faceIndex; + srvDesc.Texture2DArray.ArraySize = 1; + + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + level; + rtvDesc.Texture2DArray.FirstArraySlice = faceIndex; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); + } + else if (mDepthStencilFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_DEPTH_STENCIL_VIEW_DESC dsvDesc; + dsvDesc.Format = mDepthStencilFormat; + dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY; + dsvDesc.Flags = 0; + dsvDesc.Texture2DArray.MipSlice = mTopLevel + level; + dsvDesc.Texture2DArray.FirstArraySlice = faceIndex; + dsvDesc.Texture2DArray.ArraySize = 1; + + ID3D11DepthStencilView *dsv; + result = device->CreateDepthStencilView(texture, &dsvDesc, &dsv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal depth stencil view for texture storage, result: 0x%X.", result); + } + + mRenderTarget[faceIndex][level] = new TextureRenderTarget11(dsv, texture, srv, mInternalFormat, getLevelWidth(level), getLevelHeight(level), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(dsv); + SafeRelease(srv); + } + else + { + UNREACHABLE(); + } } + + ASSERT(outRT); + *outRT = mRenderTarget[faceIndex][level]; + return gl::Error(GL_NO_ERROR); } -ID3D11ShaderResourceView *TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +gl::Error TextureStorage11_Cube::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const { + ASSERT(outSRV); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; @@ -1093,7 +1276,7 @@ ID3D11ShaderResourceView *TextureStorage11_Cube::createSRV(int baseLevel, int mi srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = 1; srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = 6; + srvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; } else { @@ -1102,43 +1285,22 @@ ID3D11ShaderResourceView *TextureStorage11_Cube::createSRV(int baseLevel, int mi srvDesc.TextureCube.MostDetailedMip = mTopLevel + baseLevel; } - ID3D11ShaderResourceView *SRV = NULL; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); - return SRV; + return gl::Error(GL_NO_ERROR); } -void TextureStorage11_Cube::generateMipmaps() +gl::Error TextureStorage11_Cube::getSwizzleTexture(ID3D11Resource **outTexture) { - // Base level must already be defined + ASSERT(outTexture); - for (int faceIndex = 0; faceIndex < 6; faceIndex++) - { - for (int level = 1; level < getLevelCount(); level++) - { - invalidateSwizzleCacheLevel(level); - - gl::ImageIndex srcIndex = gl::ImageIndex::MakeCube(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1); - gl::ImageIndex destIndex = gl::ImageIndex::MakeCube(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level); - - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(srcIndex)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(destIndex)); - - generateMipmapLayer(source, dest); - } - } -} - -ID3D11Resource *TextureStorage11_Cube::getSwizzleTexture() -{ if (!mSwizzleTexture) { ID3D11Device *device = mRenderer->getDevice(); @@ -1147,7 +1309,7 @@ ID3D11Resource *TextureStorage11_Cube::getSwizzleTexture() desc.Width = mTextureWidth; desc.Height = mTextureHeight; desc.MipLevels = mMipLevels; - desc.ArraySize = 6; + desc.ArraySize = CUBE_FACE_COUNT; desc.Format = mSwizzleTextureFormat; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; @@ -1158,55 +1320,54 @@ ID3D11Resource *TextureStorage11_Cube::getSwizzleTexture() HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); } - return mSwizzleTexture; + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11RenderTargetView *TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel) +gl::Error TextureStorage11_Cube::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) { - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) { - if (!mSwizzleRenderTargets[mipLevel]) + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) { - ID3D11Resource *swizzleTexture = getSwizzleTexture(); - if (!swizzleTexture) - { - return NULL; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = 6; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); + return error; } - return mSwizzleRenderTargets[mipLevel]; - } - else - { - return NULL; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = CUBE_FACE_COUNT; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); } -TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, +TextureStorage11_3D::TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) { @@ -1220,6 +1381,8 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform mSwizzleRenderTargets[i] = NULL; } + mInternalFormat = internalformat; + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); mTextureFormat = formatInfo.texFormat; mShaderResourceFormat = formatInfo.srvFormat; @@ -1229,49 +1392,13 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // If the width, height or depth are not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (width > 0 && height > 0 && depth > 0) - { - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE3D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.Depth = depth; - desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); - desc.Format = mTextureFormat; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - gl::error(GL_OUT_OF_MEMORY); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - mTextureDepth = desc.Depth; - } - } + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; initializeSerials(getLevelCount() * depth, depth); } @@ -1315,8 +1442,10 @@ TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage return static_cast(storage); } -void TextureStorage11_3D::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -1325,8 +1454,10 @@ void TextureStorage11_3D::associateImage(Image11* image, int level, int layerTar } } -bool TextureStorage11_3D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) { // This validation check should never return false. It means the Image/TextureStorage association is broken. @@ -1339,8 +1470,10 @@ bool TextureStorage11_3D::isAssociatedImageValid(int level, int layerTarget, Ima } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_3D::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -1355,8 +1488,10 @@ void TextureStorage11_3D::disassociateImage(int level, int layerTarget, Image11* } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_3D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +gl::Error TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)); if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) @@ -1372,148 +1507,188 @@ void TextureStorage11_3D::releaseAssociatedImage(int level, int layerTarget, Ima { // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to NULL too. - mAssociatedImages[level]->recoverFromAssociatedStorage(); + gl::Error error = mAssociatedImages[level]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } } } } + + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *TextureStorage11_3D::getResource() const +gl::Error TextureStorage11_3D::getResource(ID3D11Resource **outResource) { - return mTexture; + // If the width, height or depth are not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE3D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.Depth = mTextureDepth; + desc.MipLevels = mMipLevels; + desc.Format = mTextureFormat; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture3D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 3D texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11ShaderResourceView *TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +gl::Error TextureStorage11_3D::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const { + ASSERT(outSRV); + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D; srvDesc.Texture3D.MostDetailedMip = baseLevel; srvDesc.Texture3D.MipLevels = mipLevels; - ID3D11ShaderResourceView *SRV = NULL; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); - return SRV; + return gl::Error(GL_NO_ERROR); } -RenderTarget *TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureStorage11_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { int mipLevel = index.mipIndex; + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); + + if (!index.hasLayer()) { - ASSERT(mRenderTargetFormat != DXGI_FORMAT_UNKNOWN); - - if (!index.hasLayer()) + if (!mLevelRenderTargets[mipLevel]) { - if (!mLevelRenderTargets[mipLevel]) + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) { - ID3D11ShaderResourceView *srv = getSRVLevel(mipLevel); - if (!srv) - { - return NULL; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = -1; - - ID3D11RenderTargetView *rtv; - HRESULT result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mLevelRenderTargets[mipLevel] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel)); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); + return error; } - return mLevelRenderTargets[mipLevel]; - } - else - { - int layer = index.layerIndex; - - LevelLayerKey key(mipLevel, layer); - if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + ID3D11ShaderResourceView *srv = NULL; + error = getSRVLevel(mipLevel, &srv); + if (error.isError()) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; + return error; + } - // TODO, what kind of SRV is expected here? - ID3D11ShaderResourceView *srv = NULL; + ID3D11Device *device = mRenderer->getDevice(); - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = layer; - rtvDesc.Texture3D.WSize = 1; + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); + ID3D11RenderTargetView *rtv; + HRESULT result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mLevelLayerRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); } - return mLevelLayerRenderTargets[key]; + mLevelRenderTargets[mipLevel] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), getLevelDepth(mipLevel), 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); } + + ASSERT(outRT); + *outRT = mLevelRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); } - - return NULL; -} - -void TextureStorage11_3D::generateMipmaps() -{ - // Base level must already be defined - - for (int level = 1; level < getLevelCount(); level++) + else { - invalidateSwizzleCacheLevel(level); + int layer = index.layerIndex; - gl::ImageIndex srcIndex = gl::ImageIndex::Make3D(level - 1); - gl::ImageIndex destIndex = gl::ImageIndex::Make3D(level); + LevelLayerKey key(mipLevel, layer); + if (mLevelLayerRenderTargets.find(key) == mLevelLayerRenderTargets.end()) + { + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(srcIndex)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(destIndex)); + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) + { + return error; + } - generateMipmapLayer(source, dest); + // TODO, what kind of SRV is expected here? + ID3D11ShaderResourceView *srv = NULL; + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = layer; + rtvDesc.Texture3D.WSize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + SafeRelease(srv); return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); + } + ASSERT(SUCCEEDED(result)); + + mLevelLayerRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + } + + ASSERT(outRT); + *outRT = mLevelLayerRenderTargets[key]; + return gl::Error(GL_NO_ERROR); } } -ID3D11Resource *TextureStorage11_3D::getSwizzleTexture() +gl::Error TextureStorage11_3D::getSwizzleTexture(ID3D11Resource **outTexture) { + ASSERT(outTexture); + if (!mSwizzleTexture) { ID3D11Device *device = mRenderer->getDevice(); @@ -1531,55 +1706,54 @@ ID3D11Resource *TextureStorage11_3D::getSwizzleTexture() HRESULT result = device->CreateTexture3D(&desc, NULL, &mSwizzleTexture); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); } - return mSwizzleTexture; + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11RenderTargetView *TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel) +gl::Error TextureStorage11_3D::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) { - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) { - if (!mSwizzleRenderTargets[mipLevel]) + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) { - ID3D11Resource *swizzleTexture = getSwizzleTexture(); - if (!swizzleTexture) - { - return NULL; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = -1; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); + return error; } - return mSwizzleRenderTargets[mipLevel]; - } - else - { - return NULL; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Texture3D.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = -1; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); } -TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, +TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels) : TextureStorage11(renderer, GetTextureBindFlags(internalformat, renderTarget)) { @@ -1591,6 +1765,8 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum in mSwizzleRenderTargets[level] = NULL; } + mInternalFormat = internalformat; + const d3d11::TextureFormat &formatInfo = d3d11::GetTextureFormatInfo(internalformat); mTextureFormat = formatInfo.texFormat; mShaderResourceFormat = formatInfo.srvFormat; @@ -1600,51 +1776,13 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum in mSwizzleShaderResourceFormat = formatInfo.swizzleSRVFormat; mSwizzleRenderTargetFormat = formatInfo.swizzleRTVFormat; - // if the width, height or depth is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (width > 0 && height > 0 && depth > 0) - { - // adjust size if needed for compressed textures - d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); + // adjust size if needed for compressed textures + d3d11::MakeValidSize(false, mTextureFormat, &width, &height, &mTopLevel); - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_TEXTURE2D_DESC desc; - desc.Width = width; - desc.Height = height; - desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); - desc.ArraySize = depth; - desc.Format = mTextureFormat; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = getBindFlags(); - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; - - HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); - - // this can happen from windows TDR - if (d3d11::isDeviceLostError(result)) - { - mRenderer->notifyDeviceLost(); - gl::error(GL_OUT_OF_MEMORY); - } - else if (FAILED(result)) - { - ASSERT(result == E_OUTOFMEMORY); - ERR("Creating image failed."); - gl::error(GL_OUT_OF_MEMORY); - } - else - { - mTexture->GetDesc(&desc); - mMipLevels = desc.MipLevels; - mTextureWidth = desc.Width; - mTextureHeight = desc.Height; - mTextureDepth = desc.ArraySize; - } - } + mMipLevels = mTopLevel + levels; + mTextureWidth = width; + mTextureHeight = height; + mTextureDepth = depth; initializeSerials(getLevelCount() * depth, depth); } @@ -1685,8 +1823,11 @@ TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray return static_cast(storage); } -void TextureStorage11_2DArray::associateImage(Image11* image, int level, int layerTarget) +void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + ASSERT(0 <= level && level < getLevelCount()); if (0 <= level && level < getLevelCount()) @@ -1696,8 +1837,11 @@ void TextureStorage11_2DArray::associateImage(Image11* image, int level, int lay } } -bool TextureStorage11_2DArray::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) +bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); // This validation check should never return false. It means the Image/TextureStorage association is broken. @@ -1707,8 +1851,11 @@ bool TextureStorage11_2DArray::isAssociatedImageValid(int level, int layerTarget } // disassociateImage allows an Image to end its association with a Storage. -void TextureStorage11_2DArray::disassociateImage(int level, int layerTarget, Image11* expectedImage) +void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage)); @@ -1721,8 +1868,11 @@ void TextureStorage11_2DArray::disassociateImage(int level, int layerTarget, Ima } // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association. -void TextureStorage11_2DArray::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) +gl::Error TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) { + GLint level = index.mipIndex; + GLint layerTarget = index.layerIndex; + LevelLayerKey key(level, layerTarget); ASSERT(mAssociatedImages.find(key) != mAssociatedImages.end()); @@ -1739,18 +1889,62 @@ void TextureStorage11_2DArray::releaseAssociatedImage(int level, int layerTarget { // Force the image to recover from storage before its data is overwritten. // This will reset mAssociatedImages[level] to NULL too. - mAssociatedImages[key]->recoverFromAssociatedStorage(); + gl::Error error = mAssociatedImages[key]->recoverFromAssociatedStorage(); + if (error.isError()) + { + return error; + } } } } + + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *TextureStorage11_2DArray::getResource() const +gl::Error TextureStorage11_2DArray::getResource(ID3D11Resource **outResource) { - return mTexture; + // if the width, height or depth is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0 && mTextureDepth > 0) + { + ASSERT(mMipLevels > 0); + + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_TEXTURE2D_DESC desc; + desc.Width = mTextureWidth; + desc.Height = mTextureHeight; + desc.MipLevels = mMipLevels; + desc.ArraySize = mTextureDepth; + desc.Format = mTextureFormat; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = getBindFlags(); + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + HRESULT result = device->CreateTexture2D(&desc, NULL, &mTexture); + + // this can happen from windows TDR + if (d3d11::isDeviceLostError(result)) + { + mRenderer->notifyDeviceLost(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + else if (FAILED(result)) + { + ASSERT(result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D array texture storage, result: 0x%X.", result); + } + } + + *outResource = mTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11ShaderResourceView *TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) +gl::Error TextureStorage11_2DArray::createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const { D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = format; @@ -1760,112 +1954,94 @@ ID3D11ShaderResourceView *TextureStorage11_2DArray::createSRV(int baseLevel, int srvDesc.Texture2DArray.FirstArraySlice = 0; srvDesc.Texture2DArray.ArraySize = mTextureDepth; - ID3D11ShaderResourceView *SRV = NULL; - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, &SRV); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal texture storage SRV, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); - return SRV; + return gl::Error(GL_NO_ERROR); } -RenderTarget *TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index) +gl::Error TextureStorage11_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { ASSERT(index.hasLayer()); int mipLevel = index.mipIndex; int layer = index.layerIndex; - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + + LevelLayerKey key(mipLevel, layer); + if (mRenderTargets.find(key) == mRenderTargets.end()) { - LevelLayerKey key(mipLevel, layer); - if (mRenderTargets.find(key) == mRenderTargets.end()) + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result; + + ID3D11Resource *texture = NULL; + gl::Error error = getResource(&texture); + if (error.isError()) { - ID3D11Device *device = mRenderer->getDevice(); - HRESULT result; + return error; + } - D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; - srvDesc.Format = mShaderResourceFormat; - srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; - srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; - srvDesc.Texture2DArray.MipLevels = 1; - srvDesc.Texture2DArray.FirstArraySlice = layer; - srvDesc.Texture2DArray.ArraySize = 1; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + srvDesc.Format = mShaderResourceFormat; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; + srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + mipLevel; + srvDesc.Texture2DArray.MipLevels = 1; + srvDesc.Texture2DArray.FirstArraySlice = layer; + srvDesc.Texture2DArray.ArraySize = 1; - ID3D11ShaderResourceView *srv; - result = device->CreateShaderResourceView(mTexture, &srvDesc, &srv); + ID3D11ShaderResourceView *srv; + result = device->CreateShaderResourceView(texture, &srvDesc, &srv); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader resource view for texture storage, result: 0x%X.", result); + } + + if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) + { + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = layer; + rtvDesc.Texture2DArray.ArraySize = 1; + + ID3D11RenderTargetView *rtv; + result = device->CreateRenderTargetView(texture, &rtvDesc, &rtv); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - if (mRenderTargetFormat != DXGI_FORMAT_UNKNOWN) - { - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = layer; - rtvDesc.Texture2DArray.ArraySize = 1; - - ID3D11RenderTargetView *rtv; - result = device->CreateRenderTargetView(mTexture, &rtvDesc, &rtv); - - if (result == E_OUTOFMEMORY) - { - SafeRelease(srv); - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); - - mRenderTargets[key] = new RenderTarget11(mRenderer, rtv, mTexture, srv, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1); - - // RenderTarget will take ownership of these resources - SafeRelease(rtv); SafeRelease(srv); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal render target view for texture storage, result: 0x%X.", result); } - else - { - UNREACHABLE(); - } + + mRenderTargets[key] = new TextureRenderTarget11(rtv, texture, srv, mInternalFormat, getLevelWidth(mipLevel), getLevelHeight(mipLevel), 1, 0); + + // RenderTarget will take ownership of these resources + SafeRelease(rtv); + SafeRelease(srv); } - - return mRenderTargets[key]; - } - else - { - return NULL; - } -} - -void TextureStorage11_2DArray::generateMipmaps() -{ - // Base level must already be defined - - for (int level = 0; level < getLevelCount(); level++) - { - invalidateSwizzleCacheLevel(level); - for (unsigned int layer = 0; layer < mTextureDepth; layer++) + else { - gl::ImageIndex sourceIndex = gl::ImageIndex::Make2DArray(level - 1, layer); - gl::ImageIndex destIndex = gl::ImageIndex::Make2DArray(level, layer); - - RenderTarget11 *source = RenderTarget11::makeRenderTarget11(getRenderTarget(sourceIndex)); - RenderTarget11 *dest = RenderTarget11::makeRenderTarget11(getRenderTarget(destIndex)); - - generateMipmapLayer(source, dest); + UNREACHABLE(); } } + + ASSERT(outRT); + *outRT = mRenderTargets[key]; + return gl::Error(GL_NO_ERROR); } -ID3D11Resource *TextureStorage11_2DArray::getSwizzleTexture() +gl::Error TextureStorage11_2DArray::getSwizzleTexture(ID3D11Resource **outTexture) { if (!mSwizzleTexture) { @@ -1886,52 +2062,51 @@ ID3D11Resource *TextureStorage11_2DArray::getSwizzleTexture() HRESULT result = device->CreateTexture2D(&desc, NULL, &mSwizzleTexture); - if (result == E_OUTOFMEMORY) + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle texture, result: 0x%X.", result); } - ASSERT(SUCCEEDED(result)); } - return mSwizzleTexture; + *outTexture = mSwizzleTexture; + return gl::Error(GL_NO_ERROR); } -ID3D11RenderTargetView *TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel) +gl::Error TextureStorage11_2DArray::getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) { - if (mipLevel >= 0 && mipLevel < getLevelCount()) + ASSERT(mipLevel >= 0 && mipLevel < getLevelCount()); + ASSERT(outRTV); + + if (!mSwizzleRenderTargets[mipLevel]) { - if (!mSwizzleRenderTargets[mipLevel]) + ID3D11Resource *swizzleTexture = NULL; + gl::Error error = getSwizzleTexture(&swizzleTexture); + if (error.isError()) { - ID3D11Resource *swizzleTexture = getSwizzleTexture(); - if (!swizzleTexture) - { - return NULL; - } - - ID3D11Device *device = mRenderer->getDevice(); - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = mSwizzleRenderTargetFormat; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; - rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; - rtvDesc.Texture2DArray.FirstArraySlice = 0; - rtvDesc.Texture2DArray.ArraySize = mTextureDepth; - - HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); - - if (result == E_OUTOFMEMORY) - { - return gl::error(GL_OUT_OF_MEMORY, static_cast(NULL)); - } - ASSERT(SUCCEEDED(result)); + return error; } - return mSwizzleRenderTargets[mipLevel]; - } - else - { - return NULL; + ID3D11Device *device = mRenderer->getDevice(); + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = mSwizzleRenderTargetFormat; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY; + rtvDesc.Texture2DArray.MipSlice = mTopLevel + mipLevel; + rtvDesc.Texture2DArray.FirstArraySlice = 0; + rtvDesc.Texture2DArray.ArraySize = mTextureDepth; + + HRESULT result = device->CreateRenderTargetView(mSwizzleTexture, &rtvDesc, &mSwizzleRenderTargets[mipLevel]); + + ASSERT(result == E_OUTOFMEMORY || SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal swizzle render target view, result: 0x%X.", result); + } } + + *outRTV = mSwizzleRenderTargets[mipLevel]; + return gl::Error(GL_NO_ERROR); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h index 9d63b2699d..930300a63d 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h @@ -25,7 +25,6 @@ namespace rx { class RenderTarget; class RenderTarget11; -class Renderer; class Renderer11; class SwapChain11; class Image11; @@ -41,47 +40,49 @@ class TextureStorage11 : public TextureStorage UINT getBindFlags() const; - virtual ID3D11Resource *getResource() const = 0; - virtual ID3D11ShaderResourceView *getSRV(const gl::SamplerState &samplerState); - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; + virtual gl::Error getResource(ID3D11Resource **outResource) = 0; + virtual gl::Error getSRV(const gl::SamplerState &samplerState, ID3D11ShaderResourceView **outSRV); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; - virtual void generateMipmaps() = 0; + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); virtual int getTopLevel() const; virtual bool isRenderTarget() const; virtual bool isManaged() const; virtual int getLevelCount() const; - UINT getSubresourceIndex(int mipLevel, int layerTarget) const; + UINT getSubresourceIndex(const gl::ImageIndex &index) const; gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); void invalidateSwizzleCacheLevel(int mipLevel); void invalidateSwizzleCache(); - bool updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level, - int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth); + gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, + const gl::ImageIndex &index, const gl::Box ©Area); - bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, int level, - int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth); + gl::Error copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, + const gl::ImageIndex &index, const gl::Box ®ion); - virtual void associateImage(Image11* image, int level, int layerTarget) = 0; - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage) = 0; - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) = 0; - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) = 0; + virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0; + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0; + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0; + + virtual gl::Error copyToStorage(TextureStorage *destStorage); + virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); protected: - TextureStorage11(Renderer *renderer, UINT bindFlags); - void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest); + TextureStorage11(Renderer11 *renderer, UINT bindFlags); int getLevelWidth(int mipLevel) const; int getLevelHeight(int mipLevel) const; int getLevelDepth(int mipLevel) const; - virtual ID3D11Resource *getSwizzleTexture() = 0; - virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel) = 0; - ID3D11ShaderResourceView *getSRVLevel(int mipLevel); + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture) = 0; + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV) = 0; + gl::Error getSRVLevel(int mipLevel, ID3D11ShaderResourceView **outSRV); - virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture) = 0; + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const = 0; void verifySwizzleExists(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha); @@ -89,6 +90,7 @@ class TextureStorage11 : public TextureStorage int mTopLevel; unsigned int mMipLevels; + GLenum mInternalFormat; DXGI_FORMAT mTextureFormat; DXGI_FORMAT mShaderResourceFormat; DXGI_FORMAT mRenderTargetFormat; @@ -115,69 +117,53 @@ class TextureStorage11 : public TextureStorage }; SwizzleCacheValue mSwizzleCache[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - struct SRVKey - { - SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); - - bool operator==(const SRVKey &rhs) const; - - int baseLevel; - int mipLevels; - bool swizzle; - }; - - struct SRVPair - { - SRVKey key; - ID3D11ShaderResourceView *srv; - }; - - struct SRVCache - { - ~SRVCache(); - - ID3D11ShaderResourceView *find(const SRVKey &key) const; - ID3D11ShaderResourceView *add(const SRVKey &key, ID3D11ShaderResourceView *srv); - - std::vector cache; - }; - private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11); const UINT mBindFlags; - SRVCache srvCache; + struct SRVKey + { + SRVKey(int baseLevel = 0, int mipLevels = 0, bool swizzle = false); + + bool operator<(const SRVKey &rhs) const; + + int baseLevel; + int mipLevels; + bool swizzle; + }; + typedef std::map SRVCache; + + SRVCache mSrvCache; ID3D11ShaderResourceView *mLevelSRVs[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureStorage11_2D : public TextureStorage11 { public: - TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain); - TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + TextureStorage11_2D(Renderer11 *renderer, SwapChain11 *swapchain); + TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual ~TextureStorage11_2D(); static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage); - virtual ID3D11Resource *getResource() const; - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual void generateMipmaps(); - - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: - virtual ID3D11Resource *getSwizzleTexture(); - virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D); - virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; ID3D11Texture2D *mTexture; RenderTarget11 *mRenderTarget[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; @@ -191,68 +177,68 @@ class TextureStorage11_2D : public TextureStorage11 class TextureStorage11_Cube : public TextureStorage11 { public: - TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + TextureStorage11_Cube(Renderer11 *renderer, GLenum internalformat, bool renderTarget, int size, int levels); virtual ~TextureStorage11_Cube(); static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage); - virtual ID3D11Resource *getResource() const; - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual void generateMipmaps(); - - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: - virtual ID3D11Resource *getSwizzleTexture(); - virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube); - virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; + + static const size_t CUBE_FACE_COUNT = 6; ID3D11Texture2D *mTexture; - RenderTarget11 *mRenderTarget[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + RenderTarget11 *mRenderTarget[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ID3D11Texture2D *mSwizzleTexture; ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; - Image11 *mAssociatedImages[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; + Image11 *mAssociatedImages[CUBE_FACE_COUNT][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; }; class TextureStorage11_3D : public TextureStorage11 { public: - TextureStorage11_3D(Renderer *renderer, GLenum internalformat, bool renderTarget, + TextureStorage11_3D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); virtual ~TextureStorage11_3D(); static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage); - virtual ID3D11Resource *getResource() const; + virtual gl::Error getResource(ID3D11Resource **outResource); // Handles both layer and non-layer RTs - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual void generateMipmaps(); - - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: - virtual ID3D11Resource *getSwizzleTexture(); - virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D); - virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; typedef std::pair LevelLayerKey; typedef std::map RenderTargetMap; @@ -270,30 +256,29 @@ class TextureStorage11_3D : public TextureStorage11 class TextureStorage11_2DArray : public TextureStorage11 { public: - TextureStorage11_2DArray(Renderer *renderer, GLenum internalformat, bool renderTarget, + TextureStorage11_2DArray(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, GLsizei depth, int levels); virtual ~TextureStorage11_2DArray(); static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage); - virtual ID3D11Resource *getResource() const; - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); + virtual gl::Error getResource(ID3D11Resource **outResource); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); - virtual void generateMipmaps(); - - virtual void associateImage(Image11* image, int level, int layerTarget); - virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage); - virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage); - virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage); + virtual void associateImage(Image11* image, const gl::ImageIndex &index); + virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage); + virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage); + virtual gl::Error releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage); protected: - virtual ID3D11Resource *getSwizzleTexture(); - virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); + virtual gl::Error getSwizzleTexture(ID3D11Resource **outTexture); + virtual gl::Error getSwizzleRenderTarget(int mipLevel, ID3D11RenderTargetView **outRTV); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray); - virtual ID3D11ShaderResourceView *createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture); + virtual gl::Error createSRV(int baseLevel, int mipLevels, DXGI_FORMAT format, ID3D11Resource *texture, + ID3D11ShaderResourceView **outSRV) const; typedef std::pair LevelLayerKey; typedef std::map RenderTargetMap; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h index 590cb9f05a..70bc3bb26f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexArray11.h @@ -19,7 +19,7 @@ class Renderer11; class VertexArray11 : public VertexArrayImpl { public: - VertexArray11(rx::Renderer11 *renderer) + VertexArray11(Renderer11 *renderer) : VertexArrayImpl(), mRenderer(renderer) { @@ -34,7 +34,7 @@ class VertexArray11 : public VertexArrayImpl private: DISALLOW_COPY_AND_ASSIGN(VertexArray11); - rx::Renderer11 *mRenderer; + Renderer11 *mRenderer; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp index 9bc5b1d2d1..a9d6fa2ca4 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp @@ -16,7 +16,7 @@ namespace rx { -VertexBuffer11::VertexBuffer11(rx::Renderer11 *const renderer) : mRenderer(renderer) +VertexBuffer11::VertexBuffer11(Renderer11 *const renderer) : mRenderer(renderer) { mBuffer = NULL; mBufferSize = 0; @@ -91,8 +91,13 @@ gl::Error VertexBuffer11::storeVertexAttributes(const gl::VertexAttribute &attri { if (buffer) { - Buffer11 *storage = Buffer11::makeBuffer11(buffer->getImplementation()); - input = static_cast(storage->getData()) + static_cast(attrib.offset); + BufferD3D *storage = BufferD3D::makeFromBuffer(buffer); + gl::Error error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); } else { @@ -132,7 +137,7 @@ gl::Error VertexBuffer11::getSpaceRequired(const gl::VertexAttribute &attrib, GL else { // Round up to divisor, if possible - elementCount = rx::UnsignedCeilDivide(static_cast(instances), attrib.divisor); + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); } gl::VertexFormat vertexFormat(attrib); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h index 0e10da1df8..a9bbac98fa 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.h @@ -18,7 +18,7 @@ class Renderer11; class VertexBuffer11 : public VertexBuffer { public: - explicit VertexBuffer11(rx::Renderer11 *const renderer); + explicit VertexBuffer11(Renderer11 *const renderer); virtual ~VertexBuffer11(); virtual gl::Error initialize(unsigned int size, bool dynamicUsage); @@ -40,7 +40,7 @@ class VertexBuffer11 : public VertexBuffer private: DISALLOW_COPY_AND_ASSIGN(VertexBuffer11); - rx::Renderer11 *const mRenderer; + Renderer11 *const mRenderer; ID3D11Buffer *mBuffer; unsigned int mBufferSize; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp index c07828757d..90a879e170 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp @@ -795,7 +795,7 @@ static D3D11ES3FormatMap BuildD3D11FormatMap() // From GL_EXT_texture_storage // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | - InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); + InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp index 2af97e73f0..121aa3bbad 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp @@ -10,6 +10,7 @@ #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h" +#include "libGLESv2/renderer/Workarounds.h" #include "libGLESv2/ProgramBinary.h" #include "libGLESv2/Framebuffer.h" @@ -95,9 +96,6 @@ #ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT # define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 #endif -#ifndef D3D11_VS_OUTPUT_REGISTER_COUNT -# define D3D11_VS_OUTPUT_REGISTER_COUNT 32 -#endif namespace rx { @@ -357,7 +355,7 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -377,7 +375,7 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; @@ -399,7 +397,7 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -421,7 +419,7 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -441,7 +439,7 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -466,7 +464,7 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -486,7 +484,7 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; @@ -506,7 +504,7 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; @@ -526,7 +524,7 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; @@ -546,7 +544,7 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; @@ -566,7 +564,7 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; @@ -586,7 +584,7 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; @@ -612,7 +610,7 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -636,7 +634,7 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -655,7 +653,7 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; @@ -677,7 +675,7 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; @@ -704,7 +702,7 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); @@ -733,7 +731,7 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); @@ -754,7 +752,7 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; @@ -778,7 +776,7 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; @@ -805,7 +803,7 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); @@ -826,7 +824,7 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); @@ -847,7 +845,7 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; @@ -868,7 +866,7 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; @@ -889,7 +887,7 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; @@ -914,7 +912,7 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; @@ -935,7 +933,7 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; @@ -951,11 +949,11 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) } } -static size_t GetMaximumStreamOutputInterleavedComponenets(D3D_FEATURE_LEVEL featureLevel) +static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif case D3D_FEATURE_LEVEL_11_0: @@ -971,14 +969,14 @@ static size_t GetMaximumStreamOutputInterleavedComponenets(D3D_FEATURE_LEVEL fea } } -static size_t GetMaximumStreamOutputSeparateCompeonents(D3D_FEATURE_LEVEL featureLevel) +static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -#if _MSC_VER >= 1700 +#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: #endif - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponenets(featureLevel) / + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / GetMaximumStreamOutputBuffers(featureLevel); @@ -1087,9 +1085,9 @@ void GenerateCaps(ID3D11Device *device, gl::Caps *caps, gl::TextureCapsMap *text caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; // Transform feedback limits - caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponenets(featureLevel); + caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel); caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel); - caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateCompeonents(featureLevel); + caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel); // GL extension support extensions->setTextureExtensionSupport(*textureCapsMap); @@ -1198,17 +1196,31 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) { -#if !defined(__MINGW32__) && defined(_DEBUG) +#if defined(_DEBUG) && !defined(__MINGW32__) return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); #else return S_OK; #endif } -RenderTarget11 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget11 **outRT) { - RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); - return RenderTarget11::makeRenderTarget11(renderTarget); + RenderTarget *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget11::makeRenderTarget11(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds() +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = true; + return workarounds; } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h index 4c05eb9256..9df9c95763 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.h @@ -12,6 +12,7 @@ #include "libGLESv2/angletypes.h" #include "libGLESv2/Caps.h" +#include "libGLESv2/Error.h" #include @@ -23,6 +24,7 @@ class FramebufferAttachment; namespace rx { class RenderTarget11; +struct Workarounds; namespace gl_d3d11 { @@ -176,7 +178,9 @@ inline void SetBufferData(ID3D11DeviceContext *context, ID3D11Buffer *constantBu context->Unmap(constantBuffer, 0); } -RenderTarget11 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment); +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget11 **outRT); + +Workarounds GenerateWorkarounds(); } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp index f061a32c52..2ca7a9cf8a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -46,10 +46,16 @@ const size_t g_shaderSize[] = namespace rx { -Blit9::Blit9(rx::Renderer9 *renderer) - : mRenderer(renderer), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedStateBlock(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL) + +Blit9::Blit9(Renderer9 *renderer) + : mRenderer(renderer), + mGeometryLoaded(false), + mQuadVertexBuffer(NULL), + mQuadVertexDeclaration(NULL), + mSavedStateBlock(NULL), + mSavedRenderTarget(NULL), + mSavedDepthStencil(NULL) { - initGeometry(); memset(mCompiledShaders, 0, sizeof(mCompiledShaders)); } @@ -65,8 +71,13 @@ Blit9::~Blit9() } } -void Blit9::initGeometry() +gl::Error Blit9::initialize() { + if (mGeometryLoaded) + { + return gl::Error(GL_NO_ERROR); + } + static const float quad[] = { -1, -1, @@ -82,7 +93,7 @@ void Blit9::initGeometry() if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal blit vertex shader, result: 0x%X.", result); } void *lockPtr = NULL; @@ -91,7 +102,8 @@ void Blit9::initGeometry() if (FAILED(result) || lockPtr == NULL) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::error(GL_OUT_OF_MEMORY); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex shader, result: 0x%X.", result); } memcpy(lockPtr, quad, sizeof(quad)); @@ -108,14 +120,18 @@ void Blit9::initGeometry() if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::error(GL_OUT_OF_MEMORY); + SafeRelease(mQuadVertexBuffer); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock internal blit vertex declaration, result: 0x%X.", result); } + + mGeometryLoaded = true; + return gl::Error(GL_NO_ERROR); } template -bool Blit9::setShader(ShaderId source, const char *profile, - D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length), - HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) +gl::Error Blit9::setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)) { IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -130,35 +146,32 @@ bool Blit9::setShader(ShaderId source, const char *profile, const BYTE* shaderCode = g_shaderCode[source]; size_t shaderSize = g_shaderSize[source]; - shader = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize); - if (!shader) + gl::Error error = (mRenderer->*createShader)(reinterpret_cast(shaderCode), shaderSize, &shader); + if (error.isError()) { - ERR("Failed to create shader for blit operation"); - return false; + return error; } mCompiledShaders[source] = shader; } HRESULT hr = (device->*setShader)(shader); - if (FAILED(hr)) { - ERR("Failed to set shader for blit operation"); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to set shader for blit operation, result: 0x%X.", hr); } - return true; + return gl::Error(GL_NO_ERROR); } -bool Blit9::setVertexShader(ShaderId shader) +gl::Error Blit9::setVertexShader(ShaderId shader) { - return setShader(shader, "vs_2_0", &rx::Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); + return setShader(shader, "vs_2_0", &Renderer9::createVertexShader, &IDirect3DDevice9::SetVertexShader); } -bool Blit9::setPixelShader(ShaderId shader) +gl::Error Blit9::setPixelShader(ShaderId shader) { - return setShader(shader, "ps_2_0", &rx::Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); + return setShader(shader, "ps_2_0", &Renderer9::createPixelShader, &IDirect3DDevice9::SetPixelShader); } RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const @@ -175,12 +188,19 @@ RECT Blit9::getSurfaceRect(IDirect3DSurface9 *surface) const return rect; } -bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +gl::Error Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { - IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source)); - if (!texture) + gl::Error error = initialize(); + if (error.isError()) { - return false; + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, getSurfaceRect(source), &texture); + if (error.isError()) + { + return error; } IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -205,87 +225,90 @@ bool Blit9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) restoreState(); - return true; + return gl::Error(GL_NO_ERROR); } -bool Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) +gl::Error Blit9::copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) { - RenderTarget9 *renderTarget = NULL; - IDirect3DSurface9 *source = NULL; + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); - if (colorbuffer) + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) { - renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + return error; } + ASSERT(renderTarget9); - if (renderTarget) - { - source = renderTarget->getSurface(); - } - - if (!source) - { - ERR("Failed to retrieve the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + IDirect3DSurface9 *destSurface = NULL; TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true); - bool result = false; - - if (destSurface) + error = storage9->getSurfaceLevel(level, true, &destSurface); + if (error.isError()) { - result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - SafeRelease(destSurface); + return error; } + ASSERT(destSurface); + gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); + + SafeRelease(destSurface); SafeRelease(source); + return result; } -bool Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) +gl::Error Blit9::copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) { - RenderTarget9 *renderTarget = NULL; - IDirect3DSurface9 *source = NULL; + gl::Error error = initialize(); + if (error.isError()) + { + return error; + } + gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); - if (colorbuffer) + RenderTarget9 *renderTarget9 = NULL; + error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget9); + if (error.isError()) { - renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + return error; } + ASSERT(renderTarget9); - if (renderTarget) - { - source = renderTarget->getSurface(); - } - - if (!source) - { - ERR("Failed to retrieve the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + IDirect3DSurface9 *source = renderTarget9->getSurface(); + ASSERT(source); + IDirect3DSurface9 *destSurface = NULL; TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(target, level, true); - bool result = false; - - if (destSurface) + error = storage9->getCubeMapSurface(target, level, true, &destSurface); + if (error.isError()) { - result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); - SafeRelease(destSurface); + return error; } + ASSERT(destSurface); + gl::Error result = copy(source, sourceRect, destFormat, xoffset, yoffset, destSurface); + + SafeRelease(destSurface); SafeRelease(source); + return result; } -bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +gl::Error Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) { - if (!dest) - { - return false; - } + ASSERT(source != NULL && dest != NULL); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -303,22 +326,30 @@ bool Blit9::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destF if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::error(GL_OUT_OF_MEMORY, false); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit between textures, StretchRect result: 0x%X.", result); } + + return gl::Error(GL_NO_ERROR); } else { return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest); } - return true; } -bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) +gl::Error Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest) { - IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect); - if (!texture) + gl::Error error = initialize(); + if (error.isError()) { - return false; + return error; + } + + IDirect3DTexture9 *texture = NULL; + error = copySurfaceToTexture(source, sourceRect, &texture); + if (error.isError()) + { + return error; } IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -331,7 +362,9 @@ bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLe setViewport(sourceRect, xoffset, yoffset); setCommonBlitState(); - if (setFormatConvertShaders(destFormat)) + + error = setFormatConvertShaders(destFormat); + if (!error.isError()) { render(); } @@ -340,12 +373,16 @@ bool Blit9::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLe restoreState(); - return true; + return error; } -bool Blit9::setFormatConvertShaders(GLenum destFormat) +gl::Error Blit9::setFormatConvertShaders(GLenum destFormat) { - bool okay = setVertexShader(SHADER_VS_STANDARD); + gl::Error error = setVertexShader(SHADER_VS_STANDARD); + if (error.isError()) + { + return error; + } switch (destFormat) { @@ -356,18 +393,18 @@ bool Blit9::setFormatConvertShaders(GLenum destFormat) case GL_RG_EXT: case GL_RED_EXT: case GL_ALPHA: - okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK); + error = setPixelShader(SHADER_PS_COMPONENTMASK); break; case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: - okay = okay && setPixelShader(SHADER_PS_LUMINANCE); + error = setPixelShader(SHADER_PS_LUMINANCE); break; } - if (!okay) + if (error.isError()) { - return false; + return error; } enum { X = 0, Y = 1, Z = 2, W = 3 }; @@ -463,15 +500,12 @@ bool Blit9::setFormatConvertShaders(GLenum destFormat) mRenderer->getDevice()->SetPixelShaderConstantF(0, psConst, 2); - return true; + return gl::Error(GL_NO_ERROR); } -IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect) +gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture) { - if (!surface) - { - return NULL; - } + ASSERT(surface); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -485,7 +519,7 @@ IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal texture for blit, result: 0x%X.", result); } IDirect3DSurface9 *textureSurface; @@ -495,7 +529,7 @@ IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(texture); - return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result); } mRenderer->endScene(); @@ -507,10 +541,11 @@ IDirect3DTexture9 *Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); SafeRelease(texture); - return gl::error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result); } - return texture; + *outTexture = texture; + return gl::Error(GL_NO_ERROR); } void Blit9::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h index 46a3ee1cf3..5c7a76ce05 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h @@ -10,6 +10,7 @@ #define LIBGLESV2_BLIT9_H_ #include "common/angleutils.h" +#include "libGLESv2/Error.h" #include @@ -29,32 +30,33 @@ class Blit9 explicit Blit9(Renderer9 *renderer); ~Blit9(); + gl::Error initialize(); + // Copy from source surface to dest surface. // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) - bool copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - bool copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); + gl::Error copy2D(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); + gl::Error copyCube(gl::Framebuffer *framebuffer, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); // Copy from source surface to dest surface. // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left) // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0. - bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + gl::Error formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); // 2x2 box filter sample from source to dest. // Requires that source is RGB(A) and dest has the same format as source. - bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); private: - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; + bool mGeometryLoaded; IDirect3DVertexBuffer9 *mQuadVertexBuffer; IDirect3DVertexDeclaration9 *mQuadVertexDeclaration; - void initGeometry(); + gl::Error setFormatConvertShaders(GLenum destFormat); - bool setFormatConvertShaders(GLenum destFormat); - - bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); - IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect); + gl::Error copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest); + gl::Error copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture); void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset); void setCommonBlitState(); RECT getSurfaceRect(IDirect3DSurface9 *surface) const; @@ -74,12 +76,12 @@ class Blit9 IUnknown *mCompiledShaders[SHADER_COUNT]; template - bool setShader(ShaderId source, const char *profile, - D3DShaderType *(Renderer9::*createShader)(const DWORD *, size_t length), - HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); + gl::Error setShader(ShaderId source, const char *profile, + gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader), + HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*)); - bool setVertexShader(ShaderId shader); - bool setPixelShader(ShaderId shader); + gl::Error setVertexShader(ShaderId shader); + gl::Error setPixelShader(ShaderId shader); void render(); void saveState(); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp index c02db515a2..430fe81e50 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp @@ -13,7 +13,7 @@ namespace rx { -Buffer9::Buffer9(rx::Renderer9 *renderer) +Buffer9::Buffer9(Renderer9 *renderer) : BufferD3D(), mRenderer(renderer), mSize(0) @@ -41,7 +41,7 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) } mSize = size; - if (data) + if (data && size > 0) { memcpy(mMemory.data(), data, size); } @@ -56,9 +56,10 @@ gl::Error Buffer9::setData(const void* data, size_t size, GLenum usage) return gl::Error(GL_NO_ERROR); } -void *Buffer9::getData() +gl::Error Buffer9::getData(const uint8_t **outData) { - return mMemory.data(); + *outData = mMemory.data(); + return gl::Error(GL_NO_ERROR); } gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) @@ -72,7 +73,7 @@ gl::Error Buffer9::setSubData(const void* data, size_t size, size_t offset) } mSize = std::max(mSize, offset + size); - if (data) + if (data && size > 0) { memcpy(mMemory.data() + offset, data, size); } @@ -113,7 +114,7 @@ void Buffer9::markTransformFeedbackUsage() UNREACHABLE(); } -Renderer* Buffer9::getRenderer() +RendererD3D *Buffer9::getRenderer() { return mRenderer; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h index e78182f905..c80b009738 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Buffer9.h @@ -20,7 +20,7 @@ class Renderer9; class Buffer9 : public BufferD3D { public: - Buffer9(rx::Renderer9 *renderer); + Buffer9(Renderer9 *renderer); virtual ~Buffer9(); static Buffer9 *makeBuffer9(BufferImpl *buffer); @@ -28,11 +28,11 @@ class Buffer9 : public BufferD3D // BufferD3D implementation virtual size_t getSize() const { return mSize; } virtual bool supportsDirectBinding() const { return false; } - virtual Renderer* getRenderer(); + RendererD3D *getRenderer() override; // BufferImpl implementation virtual gl::Error setData(const void* data, size_t size, GLenum usage); - virtual void *getData(); + gl::Error getData(const uint8_t **outData) override; virtual gl::Error setSubData(const void* data, size_t size, size_t offset); virtual gl::Error copySubData(BufferImpl* source, GLintptr sourceOffset, GLintptr destOffset, GLsizeiptr size); virtual gl::Error map(size_t offset, size_t length, GLbitfield access, GLvoid **mapPtr); @@ -42,7 +42,7 @@ class Buffer9 : public BufferD3D private: DISALLOW_COPY_AND_ASSIGN(Buffer9); - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; MemoryBuffer mMemory; size_t mSize; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp index e352a5f50a..66263fe110 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. // -// Fence9.cpp: Defines the rx::Fence9 class. +// Fence9.cpp: Defines the rx::FenceNV9 class. #include "libGLESv2/renderer/d3d/d3d9/Fence9.h" #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" @@ -14,39 +14,41 @@ namespace rx { -Fence9::Fence9(rx::Renderer9 *renderer) +FenceNV9::FenceNV9(Renderer9 *renderer) + : FenceNVImpl(), + mRenderer(renderer), + mQuery(NULL) { - mRenderer = renderer; - mQuery = NULL; } -Fence9::~Fence9() +FenceNV9::~FenceNV9() { SafeRelease(mQuery); } -bool Fence9::isSet() const -{ - return mQuery != NULL; -} - -void Fence9::set() +gl::Error FenceNV9::set() { if (!mQuery) { - mQuery = mRenderer->allocateEventQuery(); - if (!mQuery) + gl::Error error = mRenderer->allocateEventQuery(&mQuery); + if (error.isError()) { - return gl::error(GL_OUT_OF_MEMORY); + return error; } } HRESULT result = mQuery->Issue(D3DISSUE_END); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + SafeRelease(mQuery); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to end event query, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); } -bool Fence9::test(bool flushCommandBuffer) +gl::Error FenceNV9::test(bool flushCommandBuffer, GLboolean *outFinished) { ASSERT(mQuery); @@ -56,17 +58,34 @@ bool Fence9::test(bool flushCommandBuffer) if (d3d9::isDeviceLostError(result)) { mRenderer->notifyDeviceLost(); - return gl::error(GL_OUT_OF_MEMORY, true); + return gl::Error(GL_OUT_OF_MEMORY, "Device was lost while querying result of an event query."); + } + else if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get query data, result: 0x%X.", result); } ASSERT(result == S_OK || result == S_FALSE); - - return (result == S_OK); + *outFinished = ((result == S_OK) ? GL_TRUE : GL_FALSE); + return gl::Error(GL_NO_ERROR); } -bool Fence9::hasError() const +gl::Error FenceNV9::finishFence(GLboolean *outFinished) { - return mRenderer->isDeviceLost(); + ASSERT(outFinished); + + while (*outFinished != GL_TRUE) + { + gl::Error error = test(true, outFinished); + if (error.isError()) + { + return error; + } + + Sleep(0); + } + + return gl::Error(GL_NO_ERROR); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h index e923a2178c..d7873d5264 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Fence9.h @@ -4,7 +4,7 @@ // found in the LICENSE file. // -// Fence9.h: Defines the rx::Fence9 class which implements rx::FenceImpl. +// Fence9.h: Defines the rx::FenceNV9 class which implements rx::FenceNVImpl. #ifndef LIBGLESV2_RENDERER_FENCE9_H_ #define LIBGLESV2_RENDERER_FENCE9_H_ @@ -15,21 +15,20 @@ namespace rx { class Renderer9; -class Fence9 : public FenceImpl +class FenceNV9 : public FenceNVImpl { public: - explicit Fence9(rx::Renderer9 *renderer); - virtual ~Fence9(); + explicit FenceNV9(Renderer9 *renderer); + virtual ~FenceNV9(); - bool isSet() const; - void set(); - bool test(bool flushCommandBuffer); - bool hasError() const; + gl::Error set(); + gl::Error test(bool flushCommandBuffer, GLboolean *outFinished); + gl::Error finishFence(GLboolean *outFinished); private: - DISALLOW_COPY_AND_ASSIGN(Fence9); + DISALLOW_COPY_AND_ASSIGN(FenceNV9); - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; IDirect3DQuery9 *mQuery; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp index 18383fba78..2a06d12942 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp @@ -17,7 +17,7 @@ #include "libGLESv2/Framebuffer.h" #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" - +#include "common/utilities.h" namespace rx { @@ -36,15 +36,23 @@ Image9::~Image9() SafeRelease(mSurface); } -void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) +gl::Error Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface) { D3DSURFACE_DESC destDesc; HRESULT result = destSurface->GetDesc(&destDesc); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the source surface description for mipmap generation, result: 0x%X.", result); + } D3DSURFACE_DESC sourceDesc; result = sourceSurface->GetDesc(&sourceDesc); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to query the destination surface description for mipmap generation, result: 0x%X.", result); + } ASSERT(sourceDesc.Format == destDesc.Format); ASSERT(sourceDesc.Width == 1 || sourceDesc.Width / 2 == destDesc.Width); @@ -56,74 +64,111 @@ void Image9::generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sour D3DLOCKED_RECT sourceLocked = {0}; result = sourceSurface->LockRect(&sourceLocked, NULL, D3DLOCK_READONLY); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface for mipmap generation, result: 0x%X.", result); + } D3DLOCKED_RECT destLocked = {0}; result = destSurface->LockRect(&destLocked, NULL, 0); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + sourceSurface->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the destination surface for mipmap generation, result: 0x%X.", result); + } const uint8_t *sourceData = reinterpret_cast(sourceLocked.pBits); uint8_t *destData = reinterpret_cast(destLocked.pBits); - if (sourceData && destData) - { - d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, - destData, destLocked.Pitch, 0); - } + ASSERT(sourceData && destData); + + d3dFormatInfo.mipGenerationFunction(sourceDesc.Width, sourceDesc.Height, 1, sourceData, sourceLocked.Pitch, 0, + destData, destLocked.Pitch, 0); destSurface->UnlockRect(); sourceSurface->UnlockRect(); + + return gl::Error(GL_NO_ERROR); } Image9 *Image9::makeImage9(Image *img) { - ASSERT(HAS_DYNAMIC_TYPE(rx::Image9*, img)); - return static_cast(img); + ASSERT(HAS_DYNAMIC_TYPE(Image9*, img)); + return static_cast(img); } -void Image9::generateMipmap(Image9 *dest, Image9 *source) +gl::Error Image9::generateMipmap(Image9 *dest, Image9 *source) { - IDirect3DSurface9 *sourceSurface = source->getSurface(); - if (sourceSurface == NULL) - return gl::error(GL_OUT_OF_MEMORY); + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = source->getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } - IDirect3DSurface9 *destSurface = dest->getSurface(); - generateMip(destSurface, sourceSurface); + IDirect3DSurface9 *destSurface = NULL; + error = dest->getSurface(&destSurface); + if (error.isError()) + { + return error; + } + + error = generateMip(destSurface, sourceSurface); + if (error.isError()) + { + return error; + } dest->markDirty(); + + return gl::Error(GL_NO_ERROR); } -void Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) +gl::Error Image9::copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source) { D3DLOCKED_RECT sourceLock = {0}; D3DLOCKED_RECT destLock = {0}; - source->LockRect(&sourceLock, NULL, 0); - dest->LockRect(&destLock, NULL, 0); + HRESULT result; - if (sourceLock.pBits && destLock.pBits) + result = source->LockRect(&sourceLock, NULL, 0); + if (FAILED(result)) { - D3DSURFACE_DESC desc; - source->GetDesc(&desc); - - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); - unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; - - unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); - ASSERT(bytes <= static_cast(sourceLock.Pitch) && - bytes <= static_cast(destLock.Pitch)); - - for(unsigned int i = 0; i < rows; i++) - { - memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); - } - - source->UnlockRect(); - dest->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); } - else UNREACHABLE(); + + result = dest->LockRect(&destLock, NULL, 0); + if (FAILED(result)) + { + source->UnlockRect(); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock source surface for copy, result: 0x%X.", result); + } + + ASSERT(sourceLock.pBits && destLock.pBits); + + D3DSURFACE_DESC desc; + source->GetDesc(&desc); + + const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(desc.Format); + unsigned int rows = desc.Height / d3dFormatInfo.blockHeight; + + unsigned int bytes = d3d9::ComputeBlockSize(desc.Format, desc.Width, d3dFormatInfo.blockHeight); + ASSERT(bytes <= static_cast(sourceLock.Pitch) && + bytes <= static_cast(destLock.Pitch)); + + for(unsigned int i = 0; i < rows; i++) + { + memcpy((char*)destLock.pBits + destLock.Pitch * i, (char*)sourceLock.pBits + sourceLock.Pitch * i, bytes); + } + + source->UnlockRect(); + dest->UnlockRect(); + + return gl::Error(GL_NO_ERROR); } -bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) +bool Image9::redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) { // 3D textures are not supported by the D3D9 backend. ASSERT(depth <= 1); @@ -160,11 +205,11 @@ bool Image9::redefine(rx::Renderer *renderer, GLenum target, GLenum internalform return false; } -void Image9::createSurface() +gl::Error Image9::createSurface() { - if(mSurface) + if (mSurface) { - return; + return gl::Error(GL_NO_ERROR); } IDirect3DTexture9 *newTexture = NULL; @@ -187,8 +232,7 @@ void Image9::createSurface() if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - ERR("Creating image surface failed."); - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create image surface, result: 0x%X.", result); } newTexture->GetSurfaceLevel(levelToFetch, &newSurface); @@ -206,35 +250,51 @@ void Image9::createSurface() D3DLOCKED_RECT lockedRect; result = newSurface->LockRect(&lockedRect, &entireRect, 0); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } d3dFormatInfo.dataInitializerFunction(mWidth, mHeight, 1, reinterpret_cast(lockedRect.pBits), lockedRect.Pitch, 0); result = newSurface->UnlockRect(); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to unlock image surface, result: 0x%X.", result); + } } } mSurface = newSurface; mDirty = false; mD3DPool = poolToUse; + + return gl::Error(GL_NO_ERROR); } -HRESULT Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT *rect) +gl::Error Image9::lock(D3DLOCKED_RECT *lockedRect, const RECT &rect) { - createSurface(); - - HRESULT result = D3DERR_INVALIDCALL; + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } if (mSurface) { - result = mSurface->LockRect(lockedRect, rect, 0); + HRESULT result = mSurface->LockRect(lockedRect, &rect, 0); ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock image surface, result: 0x%X.", result); + } mDirty = true; } - return result; + return gl::Error(GL_NO_ERROR); } void Image9::unlock() @@ -263,26 +323,43 @@ bool Image9::isDirty() const return (mSurface || d3d9::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL) && mDirty; } -IDirect3DSurface9 *Image9::getSurface() +gl::Error Image9::getSurface(IDirect3DSurface9 **outSurface) { - createSurface(); + gl::Error error = createSurface(); + if (error.isError()) + { + return error; + } - return mSurface; + *outSurface = mSurface; + return gl::Error(GL_NO_ERROR); } -void Image9::setManagedSurface2D(TextureStorage *storage, int level) +gl::Error Image9::setManagedSurface2D(TextureStorage *storage, int level) { + IDirect3DSurface9 *surface = NULL; TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - setManagedSurface(storage9->getSurfaceLevel(level, false)); + gl::Error error = storage9->getSurfaceLevel(level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); } -void Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) +gl::Error Image9::setManagedSurfaceCube(TextureStorage *storage, int face, int level) { + IDirect3DSurface9 *surface = NULL; TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - setManagedSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false)); + gl::Error error = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, false, &surface); + if (error.isError()) + { + return error; + } + return setManagedSurface(surface); } -void Image9::setManagedSurface(IDirect3DSurface9 *surface) +gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface) { D3DSURFACE_DESC desc; surface->GetDesc(&desc); @@ -292,97 +369,119 @@ void Image9::setManagedSurface(IDirect3DSurface9 *surface) { if (mSurface) { - copyLockableSurfaces(surface, mSurface); + gl::Error error = copyLockableSurfaces(surface, mSurface); SafeRelease(mSurface); + if (error.isError()) + { + return error; + } } mSurface = surface; mD3DPool = desc.Pool; } + + return gl::Error(GL_NO_ERROR); } -bool Image9::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +gl::Error Image9::copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion) { - ASSERT(getSurface() != NULL); - TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); - return copyToSurface(storage9->getSurfaceLevel(level, true), xoffset, yoffset, width, height); -} - -bool Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - ASSERT(getSurface() != NULL); - TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); - return copyToSurface(storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true), xoffset, yoffset, width, height); -} - -bool Image9::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) -{ - // 3D textures are not supported by the D3D9 backend. - UNREACHABLE(); - return false; -} - -bool Image9::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) -{ - // 2D array textures are not supported by the D3D9 backend. - UNREACHABLE(); - return false; -} - -bool Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) -{ - ASSERT(width > 0 && height > 0); - - if (!destSurface) - return false; - - IDirect3DSurface9 *sourceSurface = getSurface(); - - if (sourceSurface && sourceSurface != destSurface) + gl::Error error = createSurface(); + if (error.isError()) { - RECT rect; - rect.left = xoffset; - rect.top = yoffset; - rect.right = xoffset + width; - rect.bottom = yoffset + height; + return error; + } - POINT point = {rect.left, rect.top}; + IDirect3DSurface9 *destSurface = NULL; - IDirect3DDevice9 *device = mRenderer->getDevice(); - - if (mD3DPool == D3DPOOL_MANAGED) + if (index.type == GL_TEXTURE_2D) + { + TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage); + gl::Error error = storage9->getSurfaceLevel(index.mipIndex, true, &destSurface); + if (error.isError()) { - D3DSURFACE_DESC desc; - sourceSurface->GetDesc(&desc); - - IDirect3DSurface9 *surf = 0; - HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); - - if (SUCCEEDED(result)) - { - copyLockableSurfaces(surf, sourceSurface); - result = device->UpdateSurface(surf, &rect, destSurface, &point); - ASSERT(SUCCEEDED(result)); - SafeRelease(surf); - } + return error; } - else + } + else + { + ASSERT(gl::IsCubemapTextureTarget(index.type)); + TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage); + gl::Error error = storage9->getCubeMapSurface(index.type, index.mipIndex, true, &destSurface); + if (error.isError()) { - // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools - HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); + return error; } } + error = copyToSurface(destSurface, region.x, region.y, region.width, region.height); SafeRelease(destSurface); - return true; + return error; +} + +gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) +{ + ASSERT(width > 0 && height > 0); + ASSERT(destSurface); + + IDirect3DSurface9 *sourceSurface = NULL; + gl::Error error = getSurface(&sourceSurface); + if (error.isError()) + { + return error; + } + + ASSERT(sourceSurface && sourceSurface != destSurface); + + RECT rect; + rect.left = xoffset; + rect.top = yoffset; + rect.right = xoffset + width; + rect.bottom = yoffset + height; + + POINT point = {rect.left, rect.top}; + + IDirect3DDevice9 *device = mRenderer->getDevice(); + + if (mD3DPool == D3DPOOL_MANAGED) + { + D3DSURFACE_DESC desc; + sourceSurface->GetDesc(&desc); + + IDirect3DSurface9 *surf = 0; + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal CreateOffscreenPlainSurface call failed, result: 0x%X.", result); + } + + copyLockableSurfaces(surf, sourceSurface); + result = device->UpdateSurface(surf, &rect, destSurface, &point); + SafeRelease(surf); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + else + { + // UpdateSurface: source must be SYSTEMMEM, dest must be DEFAULT pools + HRESULT result = device->UpdateSurface(sourceSurface, &rect, destSurface, &point); + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) + { + return gl::Error(GL_OUT_OF_MEMORY, "Internal UpdateSurface call failed, result: 0x%X.", result); + } + } + + return gl::Error(GL_NO_ERROR); } // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle. -void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input) +gl::Error Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input) { // 3D textures are not supported by the D3D9 backend. ASSERT(zoffset == 0 && depth == 1); @@ -400,10 +499,10 @@ void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width }; D3DLOCKED_RECT locked; - HRESULT result = lock(&locked, &lockRect); - if (FAILED(result)) + gl::Error error = lock(&locked, lockRect); + if (error.isError()) { - return; + return error; } d3dFormatInfo.loadFunction(width, height, depth, @@ -411,10 +510,12 @@ void Image9::loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width reinterpret_cast(locked.pBits), locked.Pitch, 0); unlock(); + + return gl::Error(GL_NO_ERROR); } -void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input) +gl::Error Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input) { // 3D textures are not supported by the D3D9 backend. ASSERT(zoffset == 0 && depth == 1); @@ -437,10 +538,10 @@ void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLs }; D3DLOCKED_RECT locked; - HRESULT result = lock(&locked, &lockRect); - if (FAILED(result)) + gl::Error error = lock(&locked, lockRect); + if (error.isError()) { - return; + return error; } d3d9FormatInfo.loadFunction(width, height, depth, @@ -448,33 +549,22 @@ void Image9::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLs reinterpret_cast(locked.pBits), locked.Pitch, 0); unlock(); + + return gl::Error(GL_NO_ERROR); } // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures -void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) +gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) { + ASSERT(source); + // ES3.0 only behaviour to copy into a 3d texture ASSERT(zoffset == 0); - RenderTarget9 *renderTarget = NULL; - IDirect3DSurface9 *surface = NULL; - gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0); + RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source); - if (colorbuffer) - { - renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); - } - - if (renderTarget) - { - surface = renderTarget->getSurface(); - } - - if (!surface) - { - ERR("Failed to retrieve the render target."); - return gl::error(GL_OUT_OF_MEMORY); - } + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); IDirect3DDevice9 *device = mRenderer->getDevice(); @@ -486,212 +576,200 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, if (FAILED(result)) { - ERR("Could not create matching destination surface."); SafeRelease(surface); - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Could not create matching destination surface, result: 0x%X.", result); } result = device->GetRenderTargetData(surface, renderTargetData); if (FAILED(result)) { - ERR("GetRenderTargetData unexpectedly failed."); SafeRelease(renderTargetData); SafeRelease(surface); - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "GetRenderTargetData unexpectedly failed, result: 0x%X.", result); } - RECT sourceRect = {x, y, x + width, y + height}; - RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height}; + int width = sourceArea.width; + int height = sourceArea.height; + + RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height }; + RECT destRect = { xoffset, yoffset, xoffset + width, yoffset + height }; D3DLOCKED_RECT sourceLock = {0}; result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0); if (FAILED(result)) { - ERR("Failed to lock the source surface (rectangle might be invalid)."); SafeRelease(renderTargetData); SafeRelease(surface); - return gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to lock the source surface (rectangle might be invalid), result: 0x%X.", result); } D3DLOCKED_RECT destLock = {0}; - result = lock(&destLock, &destRect); - - if (FAILED(result)) + gl::Error error = lock(&destLock, destRect); + if (error.isError()) { - ERR("Failed to lock the destination surface (rectangle might be invalid)."); renderTargetData->UnlockRect(); SafeRelease(renderTargetData); SafeRelease(surface); - return gl::error(GL_OUT_OF_MEMORY); + return error; } - if (destLock.pBits && sourceLock.pBits) - { - unsigned char *source = (unsigned char*)sourceLock.pBits; - unsigned char *dest = (unsigned char*)destLock.pBits; + ASSERT(destLock.pBits && sourceLock.pBits); - switch (description.Format) + unsigned char *sourcePixels = (unsigned char*)sourceLock.pBits; + unsigned char *destPixels = (unsigned char*)destLock.pBits; + + switch (description.Format) + { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + switch (getD3DFormat()) { case D3DFMT_X8R8G8B8: case D3DFMT_A8R8G8B8: - switch(getD3DFormat()) + for (int y = 0; y < height; y++) { - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - for(int y = 0; y < height; y++) - { - memcpy(dest, source, 4 * width); - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - dest[x] = source[x * 4 + 2]; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - dest[x * 2 + 0] = source[x * 4 + 2]; - dest[x * 2 + 1] = source[x * 4 + 3]; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); + memcpy(destPixels, sourcePixels, 4 * width); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; } break; - case D3DFMT_R5G6B5: - switch(getD3DFormat()) + case D3DFMT_L8: + for (int y = 0; y < height; y++) { - case D3DFMT_X8R8G8B8: - for(int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { - for(int x = 0; x < width; x++) - { - unsigned short rgb = ((unsigned short*)source)[x]; - unsigned char red = (rgb & 0xF800) >> 8; - unsigned char green = (rgb & 0x07E0) >> 3; - unsigned char blue = (rgb & 0x001F) << 3; - dest[x + 0] = blue | (blue >> 5); - dest[x + 1] = green | (green >> 6); - dest[x + 2] = red | (red >> 5); - dest[x + 3] = 0xFF; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; + destPixels[x] = sourcePixels[x * 4 + 2]; } - break; - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0xF8; - dest[x] = red | (red >> 5); - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; } break; - case D3DFMT_A1R5G5B5: - switch(getD3DFormat()) + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) { - case D3DFMT_X8R8G8B8: - for(int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { - for(int x = 0; x < width; x++) - { - unsigned short argb = ((unsigned short*)source)[x]; - unsigned char red = (argb & 0x7C00) >> 7; - unsigned char green = (argb & 0x03E0) >> 2; - unsigned char blue = (argb & 0x001F) << 3; - dest[x + 0] = blue | (blue >> 5); - dest[x + 1] = green | (green >> 5); - dest[x + 2] = red | (red >> 5); - dest[x + 3] = 0xFF; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; + destPixels[x * 2 + 0] = sourcePixels[x * 4 + 2]; + destPixels[x * 2 + 1] = sourcePixels[x * 4 + 3]; } - break; - case D3DFMT_A8R8G8B8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned short argb = ((unsigned short*)source)[x]; - unsigned char red = (argb & 0x7C00) >> 7; - unsigned char green = (argb & 0x03E0) >> 2; - unsigned char blue = (argb & 0x001F) << 3; - unsigned char alpha = (signed short)argb >> 15; - dest[x + 0] = blue | (blue >> 5); - dest[x + 1] = green | (green >> 5); - dest[x + 2] = red | (red >> 5); - dest[x + 3] = alpha; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0x7C; - dest[x] = (red << 1) | (red >> 4); - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - case D3DFMT_A8L8: - for(int y = 0; y < height; y++) - { - for(int x = 0; x < width; x++) - { - unsigned char red = source[x * 2 + 1] & 0x7C; - dest[x * 2 + 0] = (red << 1) | (red >> 4); - dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7; - } - - source += sourceLock.Pitch; - dest += destLock.Pitch; - } - break; - default: - UNREACHABLE(); + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; } break; default: UNREACHABLE(); } + break; + case D3DFMT_R5G6B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short rgb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (rgb & 0xF800) >> 8; + unsigned char green = (rgb & 0x07E0) >> 3; + unsigned char blue = (rgb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 6); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0xF8; + destPixels[x] = red | (red >> 5); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + case D3DFMT_A1R5G5B5: + switch (getD3DFormat()) + { + case D3DFMT_X8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = 0xFF; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8R8G8B8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned short argb = ((unsigned short*)sourcePixels)[x]; + unsigned char red = (argb & 0x7C00) >> 7; + unsigned char green = (argb & 0x03E0) >> 2; + unsigned char blue = (argb & 0x001F) << 3; + unsigned char alpha = (signed short)argb >> 15; + destPixels[x + 0] = blue | (blue >> 5); + destPixels[x + 1] = green | (green >> 5); + destPixels[x + 2] = red | (red >> 5); + destPixels[x + 3] = alpha; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x] = (red << 1) | (red >> 4); + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + case D3DFMT_A8L8: + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + unsigned char red = sourcePixels[x * 2 + 1] & 0x7C; + destPixels[x * 2 + 0] = (red << 1) | (red >> 4); + destPixels[x * 2 + 1] = (signed char)sourcePixels[x * 2 + 1] >> 7; + } + sourcePixels += sourceLock.Pitch; + destPixels += destLock.Pitch; + } + break; + default: + UNREACHABLE(); + } + break; + default: + UNREACHABLE(); } unlock(); @@ -701,6 +779,14 @@ void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, SafeRelease(surface); mDirty = true; + return gl::Error(GL_NO_ERROR); +} + +gl::Error Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage) +{ + // Currently unreachable, due to only being used in a D3D11-only workaround + UNIMPLEMENTED(); + return gl::Error(GL_INVALID_OPERATION); } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h index 08d8ee3545..8cc2258859 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h @@ -20,7 +20,6 @@ class Framebuffer; namespace rx { -class Renderer; class Renderer9; class Image9 : public ImageD3D @@ -31,41 +30,41 @@ class Image9 : public ImageD3D static Image9 *makeImage9(Image *img); - static void generateMipmap(Image9 *dest, Image9 *source); - static void generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); - static void copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); + static gl::Error generateMipmap(Image9 *dest, Image9 *source); + static gl::Error generateMip(IDirect3DSurface9 *destSurface, IDirect3DSurface9 *sourceSurface); + static gl::Error copyLockableSurfaces(IDirect3DSurface9 *dest, IDirect3DSurface9 *source); - virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease); + bool redefine(RendererD3D *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) override; D3DFORMAT getD3DFormat() const; virtual bool isDirty() const; - IDirect3DSurface9 *getSurface(); - virtual void setManagedSurface2D(TextureStorage *storage, int level); - virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level); - virtual bool copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); - virtual bool copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); - virtual bool copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height); + virtual gl::Error setManagedSurface2D(TextureStorage *storage, int level); + virtual gl::Error setManagedSurfaceCube(TextureStorage *storage, int face, int level); + virtual gl::Error copyToStorage(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box ®ion); - virtual void loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - GLint unpackAlignment, GLenum type, const void *input); - virtual void loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, - const void *input); + virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + GLint unpackAlignment, GLenum type, const void *input); + virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, + const void *input); - virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset,GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source); + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source); + virtual gl::Error copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, + const gl::ImageIndex &sourceIndex, TextureStorage *source); private: DISALLOW_COPY_AND_ASSIGN(Image9); - void createSurface(); - void setManagedSurface(IDirect3DSurface9 *surface); - bool copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + gl::Error getSurface(IDirect3DSurface9 **outSurface); - HRESULT lock(D3DLOCKED_RECT *lockedRect, const RECT *rect); + gl::Error createSurface(); + gl::Error setManagedSurface(IDirect3DSurface9 *surface); + gl::Error copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height); + + gl::Error lock(D3DLOCKED_RECT *lockedRect, const RECT &rect); void unlock(); - + Renderer9 *mRenderer; D3DPOOL mD3DPool; // can only be D3DPOOL_SYSTEMMEM or D3DPOOL_MANAGED since it needs to be lockable. diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h index d0970d6ac5..2375fcf4b0 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/IndexBuffer9.h @@ -40,7 +40,7 @@ class IndexBuffer9 : public IndexBuffer private: DISALLOW_COPY_AND_ASSIGN(IndexBuffer9); - rx::Renderer9 *const mRenderer; + Renderer9 *const mRenderer; IDirect3DIndexBuffer9 *mIndexBuffer; unsigned int mBufferSize; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp index 815fc01a9b..a3cab578be 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.cpp @@ -15,7 +15,7 @@ namespace rx { -Query9::Query9(rx::Renderer9 *renderer, GLenum type) +Query9::Query9(Renderer9 *renderer, GLenum type) : QueryImpl(type), mResult(GL_FALSE), mQueryFinished(false), diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h index 513e0ba6fd..36851c6c6c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Query9.h @@ -18,7 +18,7 @@ class Renderer9; class Query9 : public QueryImpl { public: - Query9(rx::Renderer9 *renderer, GLenum type); + Query9(Renderer9 *renderer, GLenum type); virtual ~Query9(); virtual gl::Error begin(); @@ -34,7 +34,7 @@ class Query9 : public QueryImpl GLuint mResult; bool mQueryFinished; - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; IDirect3DQuery9 *mQuery; }; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp index 13321ac8cd..53d1f752fa 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.cpp @@ -10,115 +10,83 @@ #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" +#include "libGLESv2/renderer/d3d/d3d9/SwapChain9.h" #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" #include "libGLESv2/main.h" namespace rx { -// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. -RenderTarget9::RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface) +RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) { - mRenderer = Renderer9::makeRenderer9(renderer); - mRenderTarget = surface; + ASSERT(HAS_DYNAMIC_TYPE(RenderTarget9*, target)); + return static_cast(target); +} + +void RenderTarget9::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +{ + // Currently a no-op +} + +// TODO: AddRef the incoming surface to take ownership instead of expecting that its ref is being given. +TextureRenderTarget9::TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples) + : mWidth(width), + mHeight(height), + mDepth(depth), + mInternalFormat(internalFormat), + mActualFormat(internalFormat), + mSamples(samples), + mRenderTarget(surface) +{ + ASSERT(mDepth == 1); if (mRenderTarget) { D3DSURFACE_DESC description; mRenderTarget->GetDesc(&description); - mWidth = description.Width; - mHeight = description.Height; - mDepth = 1; - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(description.Format); - mInternalFormat = d3dFormatInfo.internalFormat; mActualFormat = d3dFormatInfo.internalFormat; - mSamples = d3d9_gl::GetSamplesCount(description.MultiSampleType); } } -RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples) -{ - mRenderer = Renderer9::makeRenderer9(renderer); - mRenderTarget = NULL; - - const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(internalFormat); - const d3d9::D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(d3d9FormatInfo.renderFormat); - - const gl::TextureCaps &textureCaps = mRenderer->getRendererTextureCaps().get(internalFormat); - GLuint supportedSamples = textureCaps.getNearestSamples(samples); - - HRESULT result = D3DERR_INVALIDCALL; - - if (width > 0 && height > 0) - { - IDirect3DDevice9 *device = mRenderer->getDevice(); - - bool requiresInitialization = false; - - const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat); - if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) - { - result = device->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &mRenderTarget, NULL); - } - else - { - requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); - result = device->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, - gl_d3d9::GetMultisampleType(supportedSamples), - 0, FALSE, &mRenderTarget, NULL); - } - - if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) - { - gl::error(GL_OUT_OF_MEMORY); - - return; - } - - ASSERT(SUCCEEDED(result)); - - if (requiresInitialization) - { - // This format requires that the data be initialized before the render target can be used - // Unfortunately this requires a Get call on the d3d device but it is far better than having - // to mark the render target as lockable and copy data to the gpu. - IDirect3DSurface9 *prevRenderTarget = NULL; - device->GetRenderTarget(0, &prevRenderTarget); - device->SetRenderTarget(0, mRenderTarget); - device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); - device->SetRenderTarget(0, prevRenderTarget); - } - } - - mWidth = width; - mHeight = height; - mDepth = 1; - mInternalFormat = internalFormat; - mSamples = supportedSamples; - mActualFormat = d3dFormatInfo.internalFormat; -} - -RenderTarget9::~RenderTarget9() +TextureRenderTarget9::~TextureRenderTarget9() { SafeRelease(mRenderTarget); } -RenderTarget9 *RenderTarget9::makeRenderTarget9(RenderTarget *target) +GLsizei TextureRenderTarget9::getWidth() const { - ASSERT(HAS_DYNAMIC_TYPE(rx::RenderTarget9*, target)); - return static_cast(target); + return mWidth; } -void RenderTarget9::invalidate(GLint x, GLint y, GLsizei width, GLsizei height) +GLsizei TextureRenderTarget9::getHeight() const { - // Currently a no-op + return mHeight; } -IDirect3DSurface9 *RenderTarget9::getSurface() +GLsizei TextureRenderTarget9::getDepth() const +{ + return mDepth; +} + +GLenum TextureRenderTarget9::getInternalFormat() const +{ + return mInternalFormat; +} + +GLenum TextureRenderTarget9::getActualFormat() const +{ + return mActualFormat; +} + +GLsizei TextureRenderTarget9::getSamples() const +{ + return mSamples; +} + +IDirect3DSurface9 *TextureRenderTarget9::getSurface() { // Caller is responsible for releasing the returned surface reference. // TODO: remove the AddRef to match RenderTarget11 @@ -130,4 +98,51 @@ IDirect3DSurface9 *RenderTarget9::getSurface() return mRenderTarget; } + +SurfaceRenderTarget9::SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth) + : mSwapChain(swapChain), + mDepth(depth) +{ +} + +SurfaceRenderTarget9::~SurfaceRenderTarget9() +{ +} + +GLsizei SurfaceRenderTarget9::getWidth() const +{ + return mSwapChain->getWidth(); +} + +GLsizei SurfaceRenderTarget9::getHeight() const +{ + return mSwapChain->getHeight(); +} + +GLsizei SurfaceRenderTarget9::getDepth() const +{ + return 1; +} + +GLenum SurfaceRenderTarget9::getInternalFormat() const +{ + return (mDepth ? mSwapChain->GetDepthBufferInternalFormat() : mSwapChain->GetBackBufferInternalFormat()); +} + +GLenum SurfaceRenderTarget9::getActualFormat() const +{ + return d3d9::GetD3DFormatInfo(d3d9::GetTextureFormatInfo(getInternalFormat()).texFormat).internalFormat; +} + +GLsizei SurfaceRenderTarget9::getSamples() const +{ + // Our EGL surfaces do not support multisampling. + return 0; +} + +IDirect3DSurface9 *SurfaceRenderTarget9::getSurface() +{ + return (mDepth ? mSwapChain->getDepthStencil() : mSwapChain->getRenderTarget()); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h index 68d7adb49e..4585697f4c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/RenderTarget9.h @@ -14,28 +14,74 @@ namespace rx { -class Renderer; class Renderer9; +class SwapChain9; class RenderTarget9 : public RenderTarget { public: - RenderTarget9(Renderer *renderer, IDirect3DSurface9 *surface); - RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height, GLenum internalFormat, GLsizei samples); - virtual ~RenderTarget9(); + RenderTarget9() { } + virtual ~RenderTarget9() { } static RenderTarget9 *makeRenderTarget9(RenderTarget *renderTarget); - virtual void invalidate(GLint x, GLint y, GLsizei width, GLsizei height); + void invalidate(GLint x, GLint y, GLsizei width, GLsizei height) override; - IDirect3DSurface9 *getSurface(); + virtual IDirect3DSurface9 *getSurface() = 0; private: DISALLOW_COPY_AND_ASSIGN(RenderTarget9); +}; + +class TextureRenderTarget9 : public RenderTarget9 +{ + public: + TextureRenderTarget9(IDirect3DSurface9 *surface, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, + GLsizei samples); + virtual ~TextureRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLenum getActualFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + private: + DISALLOW_COPY_AND_ASSIGN(TextureRenderTarget9); + + GLsizei mWidth; + GLsizei mHeight; + GLsizei mDepth; + GLenum mInternalFormat; + GLenum mActualFormat; + GLsizei mSamples; IDirect3DSurface9 *mRenderTarget; +}; - Renderer9 *mRenderer; +class SurfaceRenderTarget9 : public RenderTarget9 +{ + public: + SurfaceRenderTarget9(SwapChain9 *swapChain, bool depth); + virtual ~SurfaceRenderTarget9(); + + GLsizei getWidth() const override; + GLsizei getHeight() const override; + GLsizei getDepth() const override; + GLenum getInternalFormat() const override; + GLenum getActualFormat() const override; + GLsizei getSamples() const override; + + IDirect3DSurface9 *getSurface() override; + + private: + DISALLOW_COPY_AND_ASSIGN(SurfaceRenderTarget9); + + SwapChain9 *mSwapChain; + bool mDepth; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp index d63f9b8582..601cd24b10 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp @@ -26,6 +26,7 @@ #include "libGLESv2/renderer/d3d/ShaderD3D.h" #include "libGLESv2/renderer/d3d/TextureD3D.h" #include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h" +#include "libGLESv2/renderer/d3d/RenderbufferD3D.h" #include "libGLESv2/main.h" #include "libGLESv2/Buffer.h" #include "libGLESv2/Texture.h" @@ -33,10 +34,12 @@ #include "libGLESv2/FramebufferAttachment.h" #include "libGLESv2/Renderbuffer.h" #include "libGLESv2/ProgramBinary.h" +#include "libGLESv2/State.h" #include "libGLESv2/angletypes.h" #include "libEGL/Display.h" +#include "common/features.h" #include "common/utilities.h" #include @@ -44,14 +47,6 @@ // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros #define REF_RAST 0 -// The "Debug This Pixel..." feature in PIX often fails when using the -// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7 -// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file. -#if !defined(ANGLE_ENABLE_D3D9EX) -// Enables use of the IDirect3D9Ex interface, when available -#define ANGLE_ENABLE_D3D9EX 1 -#endif // !defined(ANGLE_ENABLE_D3D9EX) - #if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL) #define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3 #endif @@ -96,8 +91,8 @@ enum MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4 }; -Renderer9::Renderer9(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay) - : Renderer(display), +Renderer9::Renderer9(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes) + : RendererD3D(display), mDc(hDc) { mD3d9Module = NULL; @@ -177,8 +172,8 @@ void Renderer9::release() Renderer9 *Renderer9::makeRenderer9(Renderer *renderer) { - ASSERT(HAS_DYNAMIC_TYPE(rx::Renderer9*, renderer)); - return static_cast(renderer); + ASSERT(HAS_DYNAMIC_TYPE(Renderer9*, renderer)); + return static_cast(renderer); } EGLint Renderer9::initialize() @@ -202,7 +197,7 @@ EGLint Renderer9::initialize() // Use Direct3D9Ex if available. Among other things, this version is less // inclined to report a lost context, for example when the user switches // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. - if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) { ASSERT(mD3d9Ex); mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast(&mD3d9)); @@ -386,10 +381,13 @@ void Renderer9::initializeDevice() mSceneStarted = false; - ASSERT(!mBlit && !mVertexDataManager && !mIndexDataManager); + ASSERT(!mBlit); mBlit = new Blit9(this); - mVertexDataManager = new rx::VertexDataManager(this); - mIndexDataManager = new rx::IndexDataManager(this); + mBlit->initialize(); + + ASSERT(!mVertexDataManager && !mIndexDataManager); + mVertexDataManager = new VertexDataManager(this); + mIndexDataManager = new IndexDataManager(this); } D3DPRESENT_PARAMETERS Renderer9::getDefaultPresentParameters() @@ -481,68 +479,92 @@ void Renderer9::endScene() } } -void Renderer9::sync(bool block) +gl::Error Renderer9::sync(bool block) { - HRESULT result; - - IDirect3DQuery9* query = allocateEventQuery(); - if (!query) + IDirect3DQuery9* query = NULL; + gl::Error error = allocateEventQuery(&query); + if (error.isError()) { - return; + return error; } - result = query->Issue(D3DISSUE_END); - ASSERT(SUCCEEDED(result)); - - do + HRESULT result = query->Issue(D3DISSUE_END); + if (FAILED(result)) { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to issue event query, result: 0x%X.", result); + } + + // Grab the query data once in blocking and non-blocking case + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + + // If blocking, loop until the query completes + while (block && result == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + result = query->GetData(NULL, 0, D3DGETDATA_FLUSH); - if(block && result == S_FALSE) + // explicitly check for device loss + // some drivers seem to return S_FALSE even if the device is lost + // instead of D3DERR_DEVICELOST like they should + if (result == S_FALSE && testDeviceLost(false)) { - // Keep polling, but allow other threads to do something useful first - Sleep(0); - // explicitly check for device loss - // some drivers seem to return S_FALSE even if the device is lost - // instead of D3DERR_DEVICELOST like they should - if (testDeviceLost(false)) - { - result = D3DERR_DEVICELOST; - } + result = D3DERR_DEVICELOST; } + + if (FAILED(result)) + { + if (d3d9::isDeviceLostError(result)) + { + notifyDeviceLost(); + } + + freeEventQuery(query); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get event query data, result: 0x%X.", result); + } + } - while(block && result == S_FALSE); freeEventQuery(query); - if (d3d9::isDeviceLostError(result)) - { - notifyDeviceLost(); - } + return gl::Error(GL_NO_ERROR); } -SwapChain *Renderer9::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) +SwapChain *Renderer9::createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) { - return new rx::SwapChain9(this, window, shareHandle, backBufferFormat, depthBufferFormat); + return new SwapChain9(this, nativeWindow, shareHandle, backBufferFormat, depthBufferFormat); } -IDirect3DQuery9* Renderer9::allocateEventQuery() +gl::Error Renderer9::allocateEventQuery(IDirect3DQuery9 **outQuery) { - IDirect3DQuery9 *query = NULL; - if (mEventQueryPool.empty()) { - HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); + HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, outQuery); + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate event query, result: 0x%X.", result); + } } else { - query = mEventQueryPool.back(); + *outQuery = mEventQueryPool.back(); mEventQueryPool.pop_back(); } - return query; + return gl::Error(GL_NO_ERROR); } void Renderer9::freeEventQuery(IDirect3DQuery9* query) @@ -557,14 +579,14 @@ void Renderer9::freeEventQuery(IDirect3DQuery9* query) } } -IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length) +gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader) { - return mVertexShaderCache.create(function, length); + return mVertexShaderCache.create(function, length, outShader); } -IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length) +gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader) { - return mPixelShaderCache.create(function, length); + return mPixelShaderCache.create(function, length, outShader); } HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer) @@ -604,9 +626,16 @@ QueryImpl *Renderer9::createQuery(GLenum type) return new Query9(this, type); } -FenceImpl *Renderer9::createFence() +FenceNVImpl *Renderer9::createFenceNV() { - return new Fence9(this); + return new FenceNV9(this); +} + +FenceSyncImpl *Renderer9::createFenceSync() +{ + // Renderer9 doesn't support ES 3.0 and its sync objects. + UNREACHABLE(); + return NULL; } TransformFeedbackImpl* Renderer9::createTransformFeedback() @@ -620,12 +649,12 @@ bool Renderer9::supportsFastCopyBufferToTexture(GLenum internalFormat) const return false; } -bool Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) +gl::Error Renderer9::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { // Pixel buffer objects are not supported in D3D9, since D3D9 is ES2-only and PBOs are ES3. UNREACHABLE(); - return false; + return gl::Error(GL_INVALID_OPERATION); } gl::Error Renderer9::generateSwizzle(gl::Texture *texture) @@ -635,7 +664,7 @@ gl::Error Renderer9::generateSwizzle(gl::Texture *texture) return gl::Error(GL_INVALID_OPERATION); } -gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &samplerState) +gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &samplerState) { std::vector &forceSetSamplers = (type == gl::SAMPLER_PIXEL) ? mForceSetPixelSamplerStates : mForceSetVertexSamplerStates; std::vector &appliedSamplers = (type == gl::SAMPLER_PIXEL) ? mCurPixelSamplerStates: mCurVertexSamplerStates; @@ -645,6 +674,10 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, const gl:: int d3dSamplerOffset = (type == gl::SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0; int d3dSampler = index + d3dSamplerOffset; + // Make sure to add the level offset for our tiny compressed texture workaround + TextureD3D *textureD3D = TextureD3D::makeTextureD3D(texture->getImplementation()); + DWORD baseLevel = samplerState.baseLevel + textureD3D->getNativeTexture()->getTopLevel(); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, gl_d3d9::ConvertTextureWrap(samplerState.wrapS)); mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, gl_d3d9::ConvertTextureWrap(samplerState.wrapT)); @@ -653,7 +686,7 @@ gl::Error Renderer9::setSamplerState(gl::SamplerType type, int index, const gl:: gl_d3d9::ConvertMinFilter(samplerState.minFilter, &d3dMinFilter, &d3dMipFilter, samplerState.maxAnisotropy); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter); mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter); - mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, samplerState.baseLevel); + mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXMIPLEVEL, baseLevel); if (getRendererExtensions().textureFilterAnisotropic) { mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAXANISOTROPY, (DWORD)samplerState.maxAnisotropy); @@ -684,7 +717,12 @@ gl::Error Renderer9::setTexture(gl::SamplerType type, int index, gl::Texture *te if (texStorage) { TextureStorage9 *storage9 = TextureStorage9::makeTextureStorage9(texStorage); - d3dTexture = storage9->getBaseTexture(); + + gl::Error error = storage9->getBaseTexture(&d3dTexture); + if (error.isError()) + { + return error; + } } // If we get NULL back from getBaseTexture here, something went wrong // in the texture class and we're unexpectedly missing the d3d texture @@ -751,7 +789,7 @@ gl::Error Renderer9::setRasterizerState(const gl::RasterizerState &rasterState) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, +gl::Error Renderer9::setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, unsigned int sampleMask) { bool blendStateChanged = mForceSetBlendState || memcmp(&blendState, &mCurBlendState, sizeof(gl::BlendState)) != 0; @@ -1097,13 +1135,9 @@ bool Renderer9::applyPrimitiveType(GLenum mode, GLsizei count) } -gl::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer) +gl::Error Renderer9::getNullColorbuffer(gl::FramebufferAttachment *depthbuffer, gl::FramebufferAttachment **outColorBuffer) { - if (!depthbuffer) - { - ERR("Unexpected null depthbuffer for depth-only FBO."); - return NULL; - } + ASSERT(depthbuffer); GLsizei width = depthbuffer->getWidth(); GLsizei height = depthbuffer->getHeight(); @@ -1116,11 +1150,19 @@ gl::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachme mNullColorbufferCache[i].height == height) { mNullColorbufferCache[i].lruCount = ++mMaxNullColorbufferLRU; - return mNullColorbufferCache[i].buffer; + *outColorBuffer = mNullColorbufferCache[i].buffer; + return gl::Error(GL_NO_ERROR); } } - gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(0, new gl::Colorbuffer(this, width, height, GL_NONE, 0)); + gl::Renderbuffer *nullRenderbuffer = new gl::Renderbuffer(createRenderbuffer(), 0); + gl::Error error = nullRenderbuffer->setStorage(width, height, GL_NONE, 0); + if (error.isError()) + { + SafeDelete(nullRenderbuffer); + return error; + } + gl::RenderbufferAttachment *nullbuffer = new gl::RenderbufferAttachment(GL_NONE, nullRenderbuffer); // add nullbuffer to the cache @@ -1139,40 +1181,40 @@ gl::FramebufferAttachment *Renderer9::getNullColorbuffer(gl::FramebufferAttachme oldest->width = width; oldest->height = height; - return nullbuffer; + *outColorBuffer = nullbuffer; + return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) +gl::Error Renderer9::applyRenderTarget(const gl::Framebuffer *framebuffer) { // if there is no color attachment we must synthesize a NULL colorattachment // to keep the D3D runtime happy. This should only be possible if depth texturing. gl::FramebufferAttachment *attachment = framebuffer->getColorbuffer(0); if (!attachment) { - attachment = getNullColorbuffer(framebuffer->getDepthbuffer()); - } - if (!attachment) - { - return gl::Error(GL_OUT_OF_MEMORY, "Unable to locate renderbuffer for FBO."); + gl::Error error = getNullColorbuffer(framebuffer->getDepthbuffer(), &attachment); + if (error.isError()) + { + return error; + } } + ASSERT(attachment); bool renderTargetChanged = false; unsigned int renderTargetSerial = GetAttachmentSerial(attachment); if (renderTargetSerial != mAppliedRenderTargetSerial) { // Apply the render target on the device - IDirect3DSurface9 *renderTargetSurface = NULL; - - RenderTarget9 *renderTarget = d3d9::GetAttachmentRenderTarget(attachment); - if (renderTarget) + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) { - renderTargetSurface = renderTarget->getSurface(); + return error; } + ASSERT(renderTarget); - if (!renderTargetSurface) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal render target pointer unexpectedly null."); - } + IDirect3DSurface9 *renderTargetSurface = renderTarget->getSurface(); + ASSERT(renderTargetSurface); mDevice->SetRenderTarget(0, renderTargetSurface); SafeRelease(renderTargetSurface); @@ -1204,18 +1246,16 @@ gl::Error Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) // Apply the depth stencil on the device if (depthStencil) { - IDirect3DSurface9 *depthStencilSurface = NULL; - rx::RenderTarget9 *depthStencilRenderTarget = d3d9::GetAttachmentRenderTarget(depthStencil); - - if (depthStencilRenderTarget) + RenderTarget9 *depthStencilRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(depthStencil, &depthStencilRenderTarget); + if (error.isError()) { - depthStencilSurface = depthStencilRenderTarget->getSurface(); + return error; } + ASSERT(depthStencilRenderTarget); - if (!depthStencilSurface) - { - return gl::Error(GL_OUT_OF_MEMORY, "Internal depth stencil pointer unexpectedly null."); - } + IDirect3DSurface9 *depthStencilSurface = depthStencilRenderTarget->getSurface(); + ASSERT(depthStencilSurface); mDevice->SetDepthStencilSurface(depthStencilSurface); SafeRelease(depthStencilSurface); @@ -1260,17 +1300,16 @@ gl::Error Renderer9::applyRenderTarget(gl::Framebuffer *framebuffer) return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances) +gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) { TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS]; - gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances); + gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances); if (error.isError()) { return error; } - return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw); + return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getCurrentProgramBinary(), instances, &mRepeatDraw); } // Applies the indices and element array bindings to the Direct3D 9 device @@ -1296,7 +1335,7 @@ gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *element return gl::Error(GL_NO_ERROR); } -void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) +void Renderer9::applyTransformFeedbackBuffers(const gl::State& state) { UNREACHABLE(); } @@ -1373,10 +1412,15 @@ gl::Error Renderer9::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indi // Get the raw indices for an indexed draw if (type != GL_NONE && elementArrayBuffer) { - gl::Buffer *indexBuffer = elementArrayBuffer; - BufferImpl *storage = indexBuffer->getImplementation(); + BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); intptr_t offset = reinterpret_cast(indices); - indices = static_cast(storage->getData()) + offset; + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + indices = bufferData + offset; } unsigned int startIndex = 0; @@ -1570,9 +1614,17 @@ gl::Error Renderer9::drawIndexedPoints(GLsizei count, GLenum type, const GLvoid if (elementArrayBuffer) { - BufferImpl *storage = elementArrayBuffer->getImplementation(); + BufferD3D *storage = BufferD3D::makeFromBuffer(elementArrayBuffer); intptr_t offset = reinterpret_cast(indices); - indices = static_cast(storage->getData()) + offset; + + const uint8_t *bufferData = NULL; + gl::Error error = storage->getData(&bufferData); + if (error.isError()) + { + return error; + } + + indices = bufferData + offset; } switch (type) @@ -1662,8 +1714,21 @@ gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::Ve ASSERT(!transformFeedbackActive); ASSERT(!rasterizerDiscard); - ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout); - ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer); + ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation()); + + ShaderExecutable *vertexExe = NULL; + gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe); + if (error.isError()) + { + return error; + } + + ShaderExecutable *pixelExe = NULL; + error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe); + if (error.isError()) + { + return error; + } IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL); IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL); @@ -1688,7 +1753,7 @@ gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::Ve unsigned int programSerial = programBinary->getSerial(); if (programSerial != mAppliedProgramSerial) { - programBinary->dirtyAllUniforms(); + programD3D->dirtyAllUniforms(); mDxUniformsDirty = true; mAppliedProgramSerial = programSerial; } @@ -1696,10 +1761,8 @@ gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::Ve return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::applyUniforms(const gl::ProgramBinary &programBinary) +gl::Error Renderer9::applyUniforms(const ProgramImpl &program, const std::vector &uniformArray) { - const std::vector &uniformArray = programBinary.getUniforms(); - for (size_t uniformIndex = 0; uniformIndex < uniformArray.size(); uniformIndex++) { gl::LinkedUniform *targetUniform = uniformArray[uniformIndex]; @@ -1797,7 +1860,7 @@ void Renderer9::applyUniformnbv(gl::LinkedUniform *targetUniform, const GLint *v applyUniformnfv(targetUniform, (GLfloat*)vector); } -gl::Error Renderer9::clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) +gl::Error Renderer9::clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) { if (clearParams.colorClearType != GL_FLOAT) { @@ -2219,7 +2282,7 @@ bool Renderer9::isRemovedDeviceResettable() const { bool success = false; -#ifdef ANGLE_ENABLE_D3D9EX +#if ANGLE_D3D9EX == ANGLE_ENABLED IDirect3D9Ex *d3d9Ex = NULL; typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**); Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex")); @@ -2330,82 +2393,6 @@ int Renderer9::getMaxSwapInterval() const return mMaxSwapInterval; } -bool Renderer9::copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source) -{ - bool result = false; - - if (source && dest) - { - TextureStorage9_2D *source9 = TextureStorage9_2D::makeTextureStorage9_2D(source); - TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(dest); - - int levels = source9->getLevelCount(); - for (int i = 0; i < levels; ++i) - { - IDirect3DSurface9 *srcSurf = source9->getSurfaceLevel(i, false); - IDirect3DSurface9 *dstSurf = dest9->getSurfaceLevel(i, false); - - result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); - - SafeRelease(srcSurf); - SafeRelease(dstSurf); - - if (!result) - { - return false; - } - } - } - - return result; -} - -bool Renderer9::copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source) -{ - bool result = false; - - if (source && dest) - { - TextureStorage9_Cube *source9 = TextureStorage9_Cube::makeTextureStorage9_Cube(source); - TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(dest); - int levels = source9->getLevelCount(); - for (int f = 0; f < 6; f++) - { - for (int i = 0; i < levels; i++) - { - IDirect3DSurface9 *srcSurf = source9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false); - IDirect3DSurface9 *dstSurf = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true); - - result = copyToRenderTarget(dstSurf, srcSurf, source9->isManaged()); - - SafeRelease(srcSurf); - SafeRelease(dstSurf); - - if (!result) - { - return false; - } - } - } - } - - return result; -} - -bool Renderer9::copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source) -{ - // 3D textures are not available in the D3D9 backend. - UNREACHABLE(); - return false; -} - -bool Renderer9::copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source) -{ - // 2D array textures are not supported by the D3D9 backend. - UNREACHABLE(); - return false; -} - D3DPOOL Renderer9::getBufferPool(DWORD usage) const { if (mD3d9Ex != NULL) @@ -2423,8 +2410,8 @@ D3DPOOL Renderer9::getBufferPool(DWORD usage) const return D3DPOOL_DEFAULT; } -bool Renderer9::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level) { RECT rect; rect.left = sourceRect.x; @@ -2435,8 +2422,8 @@ bool Renderer9::copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &s return mBlit->copy2D(framebuffer, rect, destFormat, xoffset, yoffset, storage, level); } -bool Renderer9::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) +gl::Error Renderer9::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level) { RECT rect; rect.left = sourceRect.x; @@ -2447,24 +2434,26 @@ bool Renderer9::copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle return mBlit->copyCube(framebuffer, rect, destFormat, xoffset, yoffset, storage, target, level); } -bool Renderer9::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) { // 3D textures are not available in the D3D9 backend. UNREACHABLE(); - return false; + return gl::Error(GL_INVALID_OPERATION); } -bool Renderer9::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) +gl::Error Renderer9::copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level) { // 2D array textures are not available in the D3D9 backend. UNREACHABLE(); - return false; + return gl::Error(GL_INVALID_OPERATION); } -bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter) +gl::Error Renderer9::blitRect(const gl::Framebuffer *readFramebuffer, const gl::Rectangle &readRect, + const gl::Framebuffer *drawFramebuffer, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, + bool blitDepth, bool blitStencil, GLenum filter) { ASSERT(filter == GL_NEAREST); @@ -2473,35 +2462,33 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & if (blitRenderTarget) { gl::FramebufferAttachment *readBuffer = readFramebuffer->getColorbuffer(0); - gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0); + ASSERT(readBuffer); + RenderTarget9 *readRenderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(readRenderTarget); + + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getColorbuffer(0); + ASSERT(drawBuffer); + RenderTarget9 *drawRenderTarget = NULL; - IDirect3DSurface9* readSurface = NULL; - IDirect3DSurface9* drawSurface = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawRenderTarget); + if (error.isError()) + { + return error; + } + ASSERT(drawRenderTarget); - if (readBuffer) - { - readRenderTarget = d3d9::GetAttachmentRenderTarget(readBuffer); - } - if (drawBuffer) - { - drawRenderTarget = d3d9::GetAttachmentRenderTarget(drawBuffer); - } + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readRenderTarget->getSurface(); + ASSERT(readSurface); - if (readRenderTarget) - { - readSurface = readRenderTarget->getSurface(); - } - if (drawRenderTarget) - { - drawSurface = drawRenderTarget->getSurface(); - } - - if (!readSurface || !drawSurface) - { - ERR("Failed to retrieve the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + IDirect3DSurface9* drawSurface = drawRenderTarget->getSurface(); + ASSERT(drawSurface); gl::Extents srcSize(readRenderTarget->getWidth(), readRenderTarget->getHeight(), 1); gl::Extents dstSize(drawRenderTarget->getWidth(), drawRenderTarget->getHeight(), 1); @@ -2594,43 +2581,40 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & if (FAILED(result)) { - ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); } } if (blitDepth || blitStencil) { gl::FramebufferAttachment *readBuffer = readFramebuffer->getDepthOrStencilbuffer(); - gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); + ASSERT(readBuffer); + RenderTarget9 *readDepthStencil = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(readBuffer, &readDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(readDepthStencil); + + gl::FramebufferAttachment *drawBuffer = drawFramebuffer->getDepthOrStencilbuffer(); + ASSERT(drawBuffer); + RenderTarget9 *drawDepthStencil = NULL; - IDirect3DSurface9* readSurface = NULL; - IDirect3DSurface9* drawSurface = NULL; + error = d3d9::GetAttachmentRenderTarget(drawBuffer, &drawDepthStencil); + if (error.isError()) + { + return error; + } + ASSERT(drawDepthStencil); - if (readBuffer) - { - readDepthStencil = d3d9::GetAttachmentRenderTarget(readBuffer); - } - if (drawBuffer) - { - drawDepthStencil = d3d9::GetAttachmentRenderTarget(drawBuffer); - } + // The getSurface calls do an AddRef so save them until after no errors are possible + IDirect3DSurface9* readSurface = readDepthStencil->getSurface(); + ASSERT(readDepthStencil); - if (readDepthStencil) - { - readSurface = readDepthStencil->getSurface(); - } - if (drawDepthStencil) - { - drawSurface = drawDepthStencil->getSurface(); - } - - if (!readSurface || !drawSurface) - { - ERR("Failed to retrieve the render target."); - return gl::error(GL_OUT_OF_MEMORY, false); - } + IDirect3DSurface9* drawSurface = drawDepthStencil->getSurface(); + ASSERT(drawDepthStencil); HRESULT result = mDevice->StretchRect(readSurface, NULL, drawSurface, NULL, D3DTEXF_NONE); @@ -2639,38 +2623,31 @@ bool Renderer9::blitRect(gl::Framebuffer *readFramebuffer, const gl::Rectangle & if (FAILED(result)) { - ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result); - return false; + return gl::Error(GL_OUT_OF_MEMORY, "Internal blit failed, StretchRect returned 0x%X.", result); } } - return true; + return gl::Error(GL_NO_ERROR); } -gl::Error Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, +gl::Error Renderer9::readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels) { ASSERT(pack.pixelBuffer.get() == NULL); - RenderTarget9 *renderTarget = NULL; - IDirect3DSurface9 *surface = NULL; gl::FramebufferAttachment *colorbuffer = framebuffer->getColorbuffer(0); + ASSERT(colorbuffer); - if (colorbuffer) + RenderTarget9 *renderTarget = NULL; + gl::Error error = d3d9::GetAttachmentRenderTarget(colorbuffer, &renderTarget); + if (error.isError()) { - renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer); + return error; } + ASSERT(renderTarget); - if (renderTarget) - { - surface = renderTarget->getSurface(); - } - - if (!surface) - { - // context must be lost - return gl::Error(GL_NO_ERROR); - } + IDirect3DSurface9 *surface = renderTarget->getSurface(); + ASSERT(surface); D3DSURFACE_DESC desc; surface->GetDesc(&desc); @@ -2825,33 +2802,67 @@ gl::Error Renderer9::readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, return gl::Error(GL_NO_ERROR); } -RenderTarget *Renderer9::createRenderTarget(SwapChain *swapChain, bool depth) +gl::Error Renderer9::createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT) { SwapChain9 *swapChain9 = SwapChain9::makeSwapChain9(swapChain); - IDirect3DSurface9 *surface = NULL; - if (depth) - { - surface = swapChain9->getDepthStencil(); - } - else - { - surface = swapChain9->getRenderTarget(); - } - - RenderTarget9 *renderTarget = new RenderTarget9(this, surface); - - return renderTarget; + *outRT = new SurfaceRenderTarget9(swapChain9, depth); + return gl::Error(GL_NO_ERROR); } -RenderTarget *Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples) +gl::Error Renderer9::createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT) { - RenderTarget9 *renderTarget = new RenderTarget9(this, width, height, format, samples); - return renderTarget; + const d3d9::TextureFormat &d3d9FormatInfo = d3d9::GetTextureFormatInfo(format); + + const gl::TextureCaps &textureCaps = getRendererTextureCaps().get(format); + GLuint supportedSamples = textureCaps.getNearestSamples(samples); + + IDirect3DSurface9 *renderTarget = NULL; + if (width > 0 && height > 0) + { + bool requiresInitialization = false; + HRESULT result = D3DERR_INVALIDCALL; + + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format); + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + result = mDevice->CreateDepthStencilSurface(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + else + { + requiresInitialization = (d3d9FormatInfo.dataInitializerFunction != NULL); + result = mDevice->CreateRenderTarget(width, height, d3d9FormatInfo.renderFormat, + gl_d3d9::GetMultisampleType(supportedSamples), + 0, FALSE, &renderTarget, NULL); + } + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create render target, result: 0x%X.", result); + } + + if (requiresInitialization) + { + // This format requires that the data be initialized before the render target can be used + // Unfortunately this requires a Get call on the d3d device but it is far better than having + // to mark the render target as lockable and copy data to the gpu. + IDirect3DSurface9 *prevRenderTarget = NULL; + mDevice->GetRenderTarget(0, &prevRenderTarget); + mDevice->SetRenderTarget(0, renderTarget); + mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 0.0f, 0); + mDevice->SetRenderTarget(0, prevRenderTarget); + } + } + + *outRT = new TextureRenderTarget9(renderTarget, format, width, height, 1, supportedSamples); + return gl::Error(GL_NO_ERROR); } -ShaderImpl *Renderer9::createShader(GLenum type) +ShaderImpl *Renderer9::createShader(const gl::Data &data, GLenum type) { - return new ShaderD3D(type, this); + return new ShaderD3D(data, type, this); } ProgramImpl *Renderer9::createProgram() @@ -2864,64 +2875,69 @@ void Renderer9::releaseShaderCompiler() ShaderD3D::releaseCompiler(); } -ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers) +gl::Error Renderer9::loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(transformFeedbackVaryings.size() == 0); - ShaderExecutable9 *executable = NULL; - switch (type) { - case rx::SHADER_VERTEX: + case SHADER_VERTEX: { - IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length); - if (vshader) + IDirect3DVertexShader9 *vshader = NULL; + gl::Error error = createVertexShader((DWORD*)function, length, &vshader); + if (error.isError()) { - executable = new ShaderExecutable9(function, length, vshader); + return error; } + *outExecutable = new ShaderExecutable9(function, length, vshader); } break; - case rx::SHADER_PIXEL: + case SHADER_PIXEL: { - IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length); - if (pshader) + IDirect3DPixelShader9 *pshader = NULL; + gl::Error error = createPixelShader((DWORD*)function, length, &pshader); + if (error.isError()) { - executable = new ShaderExecutable9(function, length, pshader); + return error; } + *outExecutable = new ShaderExecutable9(function, length, pshader); } break; default: UNREACHABLE(); - break; + return gl::Error(GL_INVALID_OPERATION); } - return executable; + return gl::Error(GL_NO_ERROR); } -ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround) +gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable) { // Transform feedback is not supported in ES2 or D3D9 ASSERT(transformFeedbackVaryings.size() == 0); - const char *profile = NULL; - + const char *profileType = NULL; switch (type) { - case rx::SHADER_VERTEX: - profile = getMajorShaderModel() >= 3 ? "vs_3_0" : "vs_2_0"; + case SHADER_VERTEX: + profileType = "vs"; break; - case rx::SHADER_PIXEL: - profile = getMajorShaderModel() >= 3 ? "ps_3_0" : "ps_2_0"; + case SHADER_PIXEL: + profileType = "ps"; break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); } + unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2; + unsigned int profileMinorVersion = 0; + std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL; @@ -2942,49 +2958,54 @@ ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const cha #endif flags |= D3DCOMPILE_DEBUG; - - std::string sourcePath = getTempPath(); - std::string sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(shaderHLSL); - writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size()); } // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options. // Try the default flags first and if compilation fails, try some alternatives. - const UINT extraFlags[] = - { - flags, - flags | D3DCOMPILE_AVOID_FLOW_CONTROL, - flags | D3DCOMPILE_PREFER_FLOW_CONTROL - }; + std::vector configs; + configs.push_back(CompileConfig(flags, "default" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL, "avoid flow control" )); + configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control")); - const static char *extraFlagNames[] = + ID3DBlob *binary = NULL; + std::string debugInfo; + gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, NULL, &binary, &debugInfo); + if (error.isError()) { - "default", - "avoid flow control", - "prefer flow control" - }; - - int attempts = ArraySize(extraFlags); - - ID3DBlob *binary = (ID3DBlob*)mCompiler.compileToBinary(infoLog, shaderHLSL, profile, extraFlags, extraFlagNames, attempts); - if (!binary) - { - return NULL; + return error; } - ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, - transformFeedbackVaryings, separatedOutputBuffers); - SafeRelease(binary); + // It's possible that binary is NULL if the compiler failed in all configurations. Set the executable to NULL + // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK. + if (!binary) + { + *outExectuable = NULL; + return gl::Error(GL_NO_ERROR); + } - return executable; + error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type, + transformFeedbackVaryings, separatedOutputBuffers, outExectuable); + + SafeRelease(binary); + if (error.isError()) + { + return error; + } + + if (!debugInfo.empty()) + { + (*outExectuable)->appendDebugInfo(debugInfo); + } + + return gl::Error(GL_NO_ERROR); } -rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize) +UniformStorage *Renderer9::createUniformStorage(size_t storageSize) { return new UniformStorage(storageSize); } -bool Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) +gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest) { return mBlit->boxFilter(source, dest); } @@ -3006,41 +3027,40 @@ D3DPOOL Renderer9::getTexturePool(DWORD usage) const return D3DPOOL_DEFAULT; } -bool Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) +gl::Error Renderer9::copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged) { - if (source && dest) + ASSERT(source && dest); + + HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + + if (fromManaged) { - HRESULT result = D3DERR_OUTOFVIDEOMEMORY; + D3DSURFACE_DESC desc; + source->GetDesc(&desc); - if (fromManaged) + IDirect3DSurface9 *surf = 0; + result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); + + if (SUCCEEDED(result)) { - D3DSURFACE_DESC desc; - source->GetDesc(&desc); - - IDirect3DSurface9 *surf = 0; - result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surf, NULL); - - if (SUCCEEDED(result)) - { - Image9::copyLockableSurfaces(surf, source); - result = mDevice->UpdateSurface(surf, NULL, dest, NULL); - SafeRelease(surf); - } - } - else - { - endScene(); - result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); - } - - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - return false; + Image9::copyLockableSurfaces(surf, source); + result = mDevice->UpdateSurface(surf, NULL, dest, NULL); + SafeRelease(surf); } } + else + { + endScene(); + result = mDevice->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE); + } - return true; + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to blit internal texture, result: 0x%X.", result); + } + + return gl::Error(GL_NO_ERROR); } Image *Renderer9::createImage() @@ -3048,11 +3068,11 @@ Image *Renderer9::createImage() return new Image9(); } -void Renderer9::generateMipmap(Image *dest, Image *src) +gl::Error Renderer9::generateMipmap(Image *dest, Image *src) { Image9 *src9 = Image9::makeImage9(src); Image9 *dst9 = Image9::makeImage9(dest); - Image9::generateMipmap(dst9, src9); + return Image9::generateMipmap(dst9, src9); } TextureStorage *Renderer9::createTextureStorage2D(SwapChain *swapChain) @@ -3099,6 +3119,19 @@ TextureImpl *Renderer9::createTexture(GLenum target) return NULL; } +RenderbufferImpl *Renderer9::createRenderbuffer() +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + return renderbuffer; +} + +RenderbufferImpl *Renderer9::createRenderbuffer(SwapChain *swapChain, bool depth) +{ + RenderbufferD3D *renderbuffer = new RenderbufferD3D(this); + renderbuffer->setStorage(swapChain, depth); + return renderbuffer; +} + bool Renderer9::getLUID(LUID *adapterLuid) const { adapterLuid->HighPart = 0; @@ -3113,7 +3146,7 @@ bool Renderer9::getLUID(LUID *adapterLuid) const return false; } -rx::VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const +VertexConversionType Renderer9::getVertexConversionType(const gl::VertexFormat &vertexFormat) const { return d3d9::GetVertexFormatInfo(getCapsDeclTypes(), vertexFormat).conversionType; } @@ -3128,4 +3161,9 @@ void Renderer9::generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCa d3d9_gl::GenerateCaps(mD3d9, mDevice, mDeviceType, mAdapter, outCaps, outTextureCaps, outExtensions); } +Workarounds Renderer9::generateWorkarounds() const +{ + return d3d9::GenerateWorkarounds(); +} + } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h index dd5f30268a..10d2fb11e8 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h @@ -11,10 +11,10 @@ #include "common/angleutils.h" #include "common/mathutil.h" -#include "libGLESv2/renderer/d3d/HLSLCompiler.h" #include "libGLESv2/renderer/d3d/d3d9/ShaderCache.h" #include "libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.h" -#include "libGLESv2/renderer/Renderer.h" +#include "libGLESv2/renderer/d3d/HLSLCompiler.h" +#include "libGLESv2/renderer/d3d/RendererD3D.h" #include "libGLESv2/renderer/RenderTarget.h" namespace gl @@ -22,6 +22,11 @@ namespace gl class FramebufferAttachment; } +namespace egl +{ +class AttributeMap; +} + namespace rx { class VertexDataManager; @@ -31,10 +36,10 @@ class StaticIndexBufferInterface; struct TranslatedAttribute; class Blit9; -class Renderer9 : public Renderer +class Renderer9 : public RendererD3D { public: - Renderer9(egl::Display *display, EGLNativeDisplayType hDc, EGLint requestedDisplay); + Renderer9(egl::Display *display, EGLNativeDisplayType hDc, const egl::AttributeMap &attributes); virtual ~Renderer9(); static Renderer9 *makeRenderer9(Renderer *renderer); @@ -48,27 +53,27 @@ class Renderer9 : public Renderer void startScene(); void endScene(); - virtual void sync(bool block); + virtual gl::Error sync(bool block); - virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); + virtual SwapChain *createSwapChain(NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); - IDirect3DQuery9* allocateEventQuery(); + gl::Error allocateEventQuery(IDirect3DQuery9 **outQuery); void freeEventQuery(IDirect3DQuery9* query); // resource creation - IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length); - IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length); + gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader); + gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader); HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer); HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer); virtual gl::Error generateSwizzle(gl::Texture *texture); - virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); + virtual gl::Error setSamplerState(gl::SamplerType type, int index, gl::Texture *texture, const gl::SamplerState &sampler); virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture); virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]); virtual gl::Error setRasterizerState(const gl::RasterizerState &rasterState); - virtual gl::Error setBlendState(gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, - unsigned int sampleMask); + gl::Error setBlendState(const gl::Framebuffer *framebuffer, const gl::BlendState &blendState, const gl::ColorF &blendColor, + unsigned int sampleMask) override; virtual gl::Error setDepthStencilState(const gl::DepthStencilState &depthStencilState, int stencilRef, int stencilBackRef, bool frontFaceCCW); @@ -76,35 +81,35 @@ class Renderer9 : public Renderer virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace, bool ignoreViewport); - virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer); + gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override; virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer, bool rasterizerDiscard, bool transformFeedbackActive); - virtual gl::Error applyUniforms(const gl::ProgramBinary &programBinary); + virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector &uniformArray); virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount); - virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[], - GLint first, GLsizei count, GLsizei instances); + virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances); virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo); - virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]); + virtual void applyTransformFeedbackBuffers(const gl::State& state); virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive); virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances); - virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer); + gl::Error clear(const gl::ClearParameters &clearParams, const gl::Framebuffer *frameBuffer) override; virtual void markAllStateDirty(); // lost device - void notifyDeviceLost(); - virtual bool isDeviceLost(); - virtual bool testDeviceLost(bool notify); - virtual bool testDeviceResettable(); + void notifyDeviceLost() override; + bool isDeviceLost() override; + bool testDeviceLost(bool notify) override; + bool testDeviceResettable() override; + + DWORD getAdapterVendor() const override; + std::string getRendererDescription() const override; + GUID getAdapterIdentifier() const override; IDirect3DDevice9 *getDevice() { return mDevice; } - virtual DWORD getAdapterVendor() const; - virtual std::string getRendererDescription() const; - virtual GUID getAdapterIdentifier() const; virtual unsigned int getReservedVertexUniformVectors() const; virtual unsigned int getReservedFragmentUniformVectors() const; @@ -119,47 +124,45 @@ class Renderer9 : public Renderer virtual int getMaxSwapInterval() const; // Pixel operations - virtual bool copyToRenderTarget2D(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTargetCube(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTarget3D(TextureStorage *dest, TextureStorage *source); - virtual bool copyToRenderTarget2DArray(TextureStorage *dest, TextureStorage *source); - - virtual bool copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); - virtual bool copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); - virtual bool copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, - GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual bool copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + virtual gl::Error copyImage2D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImageCube(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, TextureStorage *storage, GLenum target, GLint level); + virtual gl::Error copyImage3D(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); + virtual gl::Error copyImage2DArray(gl::Framebuffer *framebuffer, const gl::Rectangle &sourceRect, GLenum destFormat, + GLint xoffset, GLint yoffset, GLint zOffset, TextureStorage *storage, GLint level); - virtual bool blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, - const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter); + gl::Error blitRect(const gl::Framebuffer *readTarget, const gl::Rectangle &readRect, + const gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect, + const gl::Rectangle *scissor, bool blitRenderTarget, + bool blitDepth, bool blitStencil, GLenum filter) override; - virtual gl::Error readPixels(gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, + virtual gl::Error readPixels(const gl::Framebuffer *framebuffer, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels); // RenderTarget creation - virtual RenderTarget *createRenderTarget(SwapChain *swapChain, bool depth); - virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples); + virtual gl::Error createRenderTarget(SwapChain *swapChain, bool depth, RenderTarget **outRT); + virtual gl::Error createRenderTarget(int width, int height, GLenum format, GLsizei samples, RenderTarget **outRT); // Shader creation - virtual ShaderImpl *createShader(GLenum type); + virtual ShaderImpl *createShader(const gl::Data &data, GLenum type); virtual ProgramImpl *createProgram(); // Shader operations - virtual void releaseShaderCompiler(); - virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers); - virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const char *shaderHLSL, rx::ShaderType type, - const std::vector &transformFeedbackVaryings, - bool separatedOutputBuffers, D3DWorkaroundType workaround); + void releaseShaderCompiler() override; + virtual gl::Error loadExecutable(const void *function, size_t length, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, ShaderExecutable **outExecutable); + virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, ShaderType type, + const std::vector &transformFeedbackVaryings, + bool separatedOutputBuffers, D3DWorkaroundType workaround, + ShaderExecutable **outExectuable); virtual UniformStorage *createUniformStorage(size_t storageSize); // Image operations virtual Image *createImage(); - virtual void generateMipmap(Image *dest, Image *source); + gl::Error generateMipmap(Image *dest, Image *source) override; virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain); virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels); @@ -169,6 +172,10 @@ class Renderer9 : public Renderer // Texture creation virtual TextureImpl *createTexture(GLenum target); + // Renderbuffer creation + virtual RenderbufferImpl *createRenderbuffer(); + virtual RenderbufferImpl *createRenderbuffer(SwapChain *swapChain, bool depth); + // Buffer creation virtual BufferImpl *createBuffer(); virtual VertexBuffer *createVertexBuffer(); @@ -179,29 +186,33 @@ class Renderer9 : public Renderer // Query and Fence creation virtual QueryImpl *createQuery(GLenum type); - virtual FenceImpl *createFence(); + virtual FenceNVImpl *createFenceNV(); + virtual FenceSyncImpl *createFenceSync(); // Transform Feedback creation virtual TransformFeedbackImpl* createTransformFeedback(); // Buffer-to-texture and Texture-to-buffer copies virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const; - virtual bool fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, - GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); + virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget, + GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea); // D3D9-renderer specific methods - bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); + gl::Error boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest); D3DPOOL getTexturePool(DWORD usage) const; virtual bool getLUID(LUID *adapterLuid) const; - virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; + virtual VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const; virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const; + gl::Error copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); + private: DISALLOW_COPY_AND_ASSIGN(Renderer9); - virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const; + void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const override; + Workarounds generateWorkarounds() const override; void release(); @@ -214,8 +225,7 @@ class Renderer9 : public Renderer gl::Error getCountingIB(size_t count, StaticIndexBufferInterface **outIB); - bool copyToRenderTarget(IDirect3DSurface9 *dest, IDirect3DSurface9 *source, bool fromManaged); - gl::FramebufferAttachment *getNullColorbuffer(gl::FramebufferAttachment *depthbuffer); + gl::Error getNullColorbuffer(gl::FramebufferAttachment *depthbuffer, gl::FramebufferAttachment **outColorBuffer); D3DPOOL getBufferPool(DWORD usage) const; @@ -263,7 +273,7 @@ class Renderer9 : public Renderer unsigned int mAppliedStencilbufferSerial; bool mDepthStencilInitialized; bool mRenderTargetDescInitialized; - rx::RenderTarget::Desc mRenderTargetDesc; + RenderTarget::Desc mRenderTargetDesc; unsigned int mCurStencilSize; unsigned int mCurDepthSize; @@ -310,8 +320,8 @@ class Renderer9 : public Renderer IDirect3DPixelShader9 *mAppliedPixelShader; unsigned int mAppliedProgramSerial; - rx::dx_VertexConstants mVertexConstants; - rx::dx_PixelConstants mPixelConstants; + dx_VertexConstants mVertexConstants; + dx_PixelConstants mPixelConstants; bool mDxUniformsDirty; // A pool of event queries that are currently unused. diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h index 2ad3022839..6d7d2d648f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h @@ -10,6 +10,8 @@ #ifndef LIBGLESV2_RENDERER_SHADER_CACHE_H_ #define LIBGLESV2_RENDERER_SHADER_CACHE_H_ +#include "libGLESv2/Error.h" + #include "common/debug.h" #include @@ -37,21 +39,22 @@ class ShaderCache mDevice = device; } - ShaderObject *create(const DWORD *function, size_t length) + gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject) { std::string key(reinterpret_cast(function), length); typename Map::iterator it = mMap.find(key); if (it != mMap.end()) { it->second->AddRef(); - return it->second; + *outShaderObject = it->second; + return gl::Error(GL_NO_ERROR); } ShaderObject *shader; HRESULT result = createShader(function, &shader); if (FAILED(result)) { - return NULL; + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result); } // Random eviction policy. @@ -64,7 +67,8 @@ class ShaderCache shader->AddRef(); mMap[key] = shader; - return shader; + *outShaderObject = shader; + return gl::Error(GL_NO_ERROR); } void clear() diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp index 0aeaabb1ca..95eb1a4371 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp @@ -11,12 +11,15 @@ #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" +#include "common/features.h" + namespace rx { -SwapChain9::SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle, +SwapChain9::SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) + : mRenderer(renderer), + SwapChain(nativeWindow, shareHandle, backBufferFormat, depthBufferFormat) { mSwapChain = NULL; mBackBuffer = NULL; @@ -41,7 +44,7 @@ void SwapChain9::release() SafeRelease(mRenderTarget); SafeRelease(mOffscreenTexture); - if (mWindow) + if (mNativeWindow.getNativeWindow()) { mShareHandle = NULL; } @@ -49,7 +52,7 @@ void SwapChain9::release() static DWORD convertInterval(EGLint interval) { -#ifdef ANGLE_FORCE_VSYNC_OFF +#if ANGLE_VSYNC == ANGLE_DISABLED return D3DPRESENT_INTERVAL_IMMEDIATE; #else switch(interval) @@ -95,7 +98,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI SafeRelease(mDepthStencil); HANDLE *pShareHandle = NULL; - if (!mWindow && mRenderer->getShareHandleSupport()) + if (!mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport()) { pShareHandle = &mShareHandle; } @@ -152,7 +155,8 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI const d3d9::TextureFormat &depthBufferd3dFormatInfo = d3d9::GetTextureFormatInfo(mDepthBufferFormat); - if (mWindow) + EGLNativeWindowType window = mNativeWindow.getNativeWindow(); + if (window) { D3DPRESENT_PARAMETERS presentParameters = {0}; presentParameters.AutoDepthStencilFormat = depthBufferd3dFormatInfo.renderFormat; @@ -160,7 +164,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI presentParameters.BackBufferFormat = backBufferd3dFormatInfo.renderFormat; presentParameters.EnableAutoDepthStencil = FALSE; presentParameters.Flags = 0; - presentParameters.hDeviceWindow = mWindow; + presentParameters.hDeviceWindow = window; presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented presentParameters.PresentationInterval = convertInterval(swapInterval); @@ -203,7 +207,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI result = mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); ASSERT(SUCCEEDED(result)); - InvalidateRect(mWindow, NULL, FALSE); + InvalidateRect(window, NULL, FALSE); } if (mDepthBufferFormat != GL_NONE) @@ -238,7 +242,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI } // parameters should be validated/clamped by caller -EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint) +EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) { if (!mSwapChain) { @@ -379,8 +383,8 @@ IDirect3DTexture9 *SwapChain9::getOffscreenTexture() SwapChain9 *SwapChain9::makeSwapChain9(SwapChain *swapChain) { - ASSERT(HAS_DYNAMIC_TYPE(rx::SwapChain9*, swapChain)); - return static_cast(swapChain); + ASSERT(HAS_DYNAMIC_TYPE(SwapChain9*, swapChain)); + return static_cast(swapChain); } void SwapChain9::recreate() diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h index 4d756f80d1..cb33bfbc0c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h @@ -19,19 +19,22 @@ class Renderer9; class SwapChain9 : public SwapChain { public: - SwapChain9(Renderer9 *renderer, HWND window, HANDLE shareHandle, + SwapChain9(Renderer9 *renderer, NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); virtual ~SwapChain9(); EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); - virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint); + virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); virtual void recreate(); virtual IDirect3DSurface9 *getRenderTarget(); virtual IDirect3DSurface9 *getDepthStencil(); virtual IDirect3DTexture9 *getOffscreenTexture(); + EGLint getWidth() const { return mWidth; } + EGLint getHeight() const { return mHeight; } + static SwapChain9 *makeSwapChain9(SwapChain *swapChain); private: diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp index f44e33db18..0ff4fd3b0f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp @@ -20,8 +20,13 @@ namespace rx { -TextureStorage9::TextureStorage9(Renderer *renderer, DWORD usage) +TextureStorage9::TextureStorage9(Renderer9 *renderer, DWORD usage) : mTopLevel(0), + mMipLevels(0), + mTextureWidth(0), + mTextureHeight(0), + mInternalFormat(GL_NONE), + mTextureFormat(D3DFMT_UNKNOWN), mRenderer(Renderer9::makeRenderer9(renderer)), mD3DUsage(usage), mD3DPool(mRenderer->getTexturePool(usage)) @@ -84,44 +89,52 @@ int TextureStorage9::getTopLevel() const int TextureStorage9::getLevelCount() const { - return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0; + return mMipLevels - mTopLevel; } -TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain) +gl::Error TextureStorage9::setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData) +{ + UNREACHABLE(); + return gl::Error(GL_INVALID_OPERATION); +} + +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain) : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET) { IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture(); mTexture = surfaceTexture; + mMipLevels = surfaceTexture->GetLevelCount(); + + mInternalFormat = swapchain->GetBackBufferInternalFormat(); + + D3DSURFACE_DESC surfaceDesc; + surfaceTexture->GetLevelDesc(0, &surfaceDesc); + mTextureWidth = surfaceDesc.Width; + mTextureHeight = surfaceDesc.Height; + mTextureFormat = surfaceDesc.Format; + mRenderTarget = NULL; - initializeRenderTarget(); initializeSerials(1, 1); } -TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) +TextureStorage9_2D::TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) { mTexture = NULL; mRenderTarget = NULL; - // if the width or height is not positive this should be treated as an incomplete texture - // we handle that here by skipping the d3d texture creation - if (width > 0 && height > 0) - { - IDirect3DDevice9 *device = mRenderer->getDevice(); - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); - d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); - UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; - HRESULT result = device->CreateTexture(width, height, creationLevels, getUsage(), d3dFormatInfo.texFormat, getPool(), &mTexture, NULL); + mInternalFormat = internalformat; - if (FAILED(result)) - { - ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - gl::error(GL_OUT_OF_MEMORY); - } - } + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &width, &height, &mTopLevel); + mTextureWidth = width; + mTextureHeight = height; + mMipLevels = mTopLevel + levels; - initializeRenderTarget(); initializeSerials(getLevelCount(), 1); } @@ -139,104 +152,168 @@ TextureStorage9_2D *TextureStorage9_2D::makeTextureStorage9_2D(TextureStorage *s // Increments refcount on surface. // caller must Release() the returned surface -IDirect3DSurface9 *TextureStorage9_2D::getSurfaceLevel(int level, bool dirty) +gl::Error TextureStorage9_2D::getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface) { - IDirect3DSurface9 *surface = NULL; - - if (mTexture) + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) { - HRESULT result = mTexture->GetSurfaceLevel(level + mTopLevel, &surface); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - // With managed textures the driver needs to be informed of updates to the lower mipmap levels - if (level + mTopLevel != 0 && isManaged() && dirty) - { - mTexture->AddDirtyRect(NULL); - } + return error; } - return surface; -} + IDirect3DTexture9 *texture = static_cast(baseTexture); -RenderTarget *TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/) -{ - return mRenderTarget; -} + HRESULT result = texture->GetSurfaceLevel(level + mTopLevel, outSurface); -void TextureStorage9_2D::generateMipmaps() -{ - // Base level must already be defined - - for (int level = 1; level < getLevelCount(); level++) + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) { - IDirect3DSurface9 *upper = getSurfaceLevel(level - 1, false); - IDirect3DSurface9 *lower = getSurfaceLevel(level, true); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); + } - if (upper != NULL && lower != NULL) + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level + mTopLevel != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(NULL); + } + + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::getRenderTarget(const gl::ImageIndex &/*index*/, RenderTarget **outRT) +{ + if (!mRenderTarget && isRenderTarget()) + { + IDirect3DSurface9 *surface = NULL; + gl::Error error = getSurfaceLevel(0, false, &surface); + if (error.isError()) { - mRenderer->boxFilter(upper, lower); + return error; } + mRenderTarget = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); + } + + ASSERT(outRT); + *outRT = mRenderTarget; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getSurfaceLevel(sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getSurfaceLevel(destIndex.mipIndex, true, &lower); + if (error.isError()) + { SafeRelease(upper); - SafeRelease(lower); - } -} - -IDirect3DBaseTexture9 *TextureStorage9_2D::getBaseTexture() const -{ - return mTexture; -} - -void TextureStorage9_2D::initializeRenderTarget() -{ - ASSERT(mRenderTarget == NULL); - - if (mTexture != NULL && isRenderTarget()) - { - IDirect3DSurface9 *surface = getSurfaceLevel(0, false); - - mRenderTarget = new RenderTarget9(mRenderer, surface); - } -} - -TextureStorage9_Cube::TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels) - : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) -{ - mTexture = NULL; - for (int i = 0; i < 6; ++i) - { - mRenderTarget[i] = NULL; + return error; } - // if the size is not positive this should be treated as an incomplete texture + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_2D::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // if the width or height is not positive this should be treated as an incomplete texture // we handle that here by skipping the d3d texture creation - if (size > 0) + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) { - IDirect3DDevice9 *device = mRenderer->getDevice(); - int height = size; - const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); - d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); - UINT creationLevels = (levels == 0) ? 0 : mTopLevel + levels; + ASSERT(mMipLevels > 0); - HRESULT result = device->CreateCubeTexture(size, creationLevels, getUsage(), d3dFormatInfo.texFormat, getPool(), &mTexture, NULL); + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateTexture(mTextureWidth, mTextureHeight, mMipLevels, getUsage(), mTextureFormat, + getPool(), &mTexture, NULL); if (FAILED(result)) { ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); - gl::error(GL_OUT_OF_MEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create 2D storage texture, result: 0x%X.", result); } } - initializeRenderTarget(); - initializeSerials(getLevelCount() * 6, 6); + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_2D::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_2D *dest9 = TextureStorage9_2D::makeTextureStorage9_2D(destStorage); + + int levels = getLevelCount(); + for (int i = 0; i < levels; ++i) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getSurfaceLevel(i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getSurfaceLevel(i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + + return gl::Error(GL_NO_ERROR); +} + +TextureStorage9_Cube::TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels) + : TextureStorage9(renderer, GetTextureUsage(internalformat, renderTarget)) +{ + mTexture = NULL; + for (int i = 0; i < CUBE_FACE_COUNT; ++i) + { + mRenderTarget[i] = NULL; + } + + mInternalFormat = internalformat; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalformat); + mTextureFormat = d3dFormatInfo.texFormat; + + int height = size; + d3d9::MakeValidSize(false, d3dFormatInfo.texFormat, &size, &height, &mTopLevel); + mTextureWidth = size; + mTextureHeight = size; + mMipLevels = mTopLevel + levels; + + initializeSerials(getLevelCount() * CUBE_FACE_COUNT, CUBE_FACE_COUNT); } TextureStorage9_Cube::~TextureStorage9_Cube() { SafeRelease(mTexture); - for (int i = 0; i < 6; ++i) + for (int i = 0; i < CUBE_FACE_COUNT; ++i) { SafeDelete(mRenderTarget[i]); } @@ -250,74 +327,146 @@ TextureStorage9_Cube *TextureStorage9_Cube::makeTextureStorage9_Cube(TextureStor // Increments refcount on surface. // caller must Release() the returned surface -IDirect3DSurface9 *TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty) +gl::Error TextureStorage9_Cube::getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface) { - IDirect3DSurface9 *surface = NULL; - - if (mTexture) + IDirect3DBaseTexture9 *baseTexture = NULL; + gl::Error error = getBaseTexture(&baseTexture); + if (error.isError()) { - D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); - HRESULT result = mTexture->GetCubeMapSurface(face, level + mTopLevel, &surface); - UNUSED_ASSERTION_VARIABLE(result); - ASSERT(SUCCEEDED(result)); - - // With managed textures the driver needs to be informed of updates to the lower mipmap levels - if (level != 0 && isManaged() && dirty) - { - mTexture->AddDirtyRect(face, NULL); - } + return error; } - return surface; -} + IDirect3DCubeTexture9 *texture = static_cast(baseTexture); -RenderTarget *TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index) -{ - return mRenderTarget[index.layerIndex]; -} + D3DCUBEMAP_FACES face = gl_d3d9::ConvertCubeFace(faceTarget); + HRESULT result = texture->GetCubeMapSurface(face, level + mTopLevel, outSurface); -void TextureStorage9_Cube::generateMipmaps() -{ - // Base level must already be defined - - for (int faceIndex = 0; faceIndex < 6; faceIndex++) + ASSERT(SUCCEEDED(result)); + if (FAILED(result)) { - for (int level = 1; level < getLevelCount(); level++) - { - IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level - 1, false); - IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, level, true); - - if (upper != NULL && lower != NULL) - { - mRenderer->boxFilter(upper, lower); - } - - SafeRelease(upper); - SafeRelease(lower); - } + return gl::Error(GL_OUT_OF_MEMORY, "Failed to get the surface from a texture, result: 0x%X.", result); } + + // With managed textures the driver needs to be informed of updates to the lower mipmap levels + if (level != 0 && isManaged() && dirty) + { + texture->AddDirtyRect(face, NULL); + } + + return gl::Error(GL_NO_ERROR); } -IDirect3DBaseTexture9 *TextureStorage9_Cube::getBaseTexture() const +gl::Error TextureStorage9_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) { - return mTexture; -} + ASSERT(outRT); + ASSERT(index.mipIndex == 0); + ASSERT(index.layerIndex >= 0 && index.layerIndex < CUBE_FACE_COUNT); -void TextureStorage9_Cube::initializeRenderTarget() -{ - if (mTexture != NULL && isRenderTarget()) + if (mRenderTarget[index.layerIndex] == NULL && isRenderTarget()) { IDirect3DSurface9 *surface = NULL; - - for (int i = 0; i < 6; ++i) + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index.layerIndex, 0, false, &surface); + if (error.isError()) { - ASSERT(mRenderTarget[i] == NULL); - - surface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, false); - - mRenderTarget[i] = new RenderTarget9(mRenderer, surface); + return error; } + + mRenderTarget[index.layerIndex] = new TextureRenderTarget9(surface, mInternalFormat, mTextureWidth, mTextureHeight, 1, 0); } + + *outRT = mRenderTarget[index.layerIndex]; + return gl::Error(GL_NO_ERROR); } -} \ No newline at end of file +gl::Error TextureStorage9_Cube::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) +{ + IDirect3DSurface9 *upper = NULL; + gl::Error error = getCubeMapSurface(sourceIndex.type, sourceIndex.mipIndex, false, &upper); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *lower = NULL; + error = getCubeMapSurface(destIndex.type, destIndex.mipIndex, true, &lower); + if (error.isError()) + { + SafeRelease(upper); + return error; + } + + ASSERT(upper && lower); + error = mRenderer->boxFilter(upper, lower); + + SafeRelease(upper); + SafeRelease(lower); + + return error; +} + +gl::Error TextureStorage9_Cube::getBaseTexture(IDirect3DBaseTexture9 **outTexture) +{ + // if the size is not positive this should be treated as an incomplete texture + // we handle that here by skipping the d3d texture creation + if (mTexture == NULL && mTextureWidth > 0 && mTextureHeight > 0) + { + ASSERT(mMipLevels > 0); + ASSERT(mTextureWidth == mTextureHeight); + + IDirect3DDevice9 *device = mRenderer->getDevice(); + HRESULT result = device->CreateCubeTexture(mTextureWidth, mMipLevels, getUsage(), mTextureFormat, getPool(), + &mTexture, NULL); + + if (FAILED(result)) + { + ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY); + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create cube storage texture, result: 0x%X.", result); + } + } + + *outTexture = mTexture; + return gl::Error(GL_NO_ERROR); +} + +gl::Error TextureStorage9_Cube::copyToStorage(TextureStorage *destStorage) +{ + ASSERT(destStorage); + + TextureStorage9_Cube *dest9 = TextureStorage9_Cube::makeTextureStorage9_Cube(destStorage); + + int levels = getLevelCount(); + for (int f = 0; f < CUBE_FACE_COUNT; f++) + { + for (int i = 0; i < levels; i++) + { + IDirect3DSurface9 *srcSurf = NULL; + gl::Error error = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, false, &srcSurf); + if (error.isError()) + { + return error; + } + + IDirect3DSurface9 *dstSurf = NULL; + error = dest9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i, true, &dstSurf); + if (error.isError()) + { + SafeRelease(srcSurf); + return error; + } + + error = mRenderer->copyToRenderTarget(dstSurf, srcSurf, isManaged()); + + SafeRelease(srcSurf); + SafeRelease(dstSurf); + + if (error.isError()) + { + return error; + } + } + } + + return gl::Error(GL_NO_ERROR); +} + +} diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h index e698c7dd56..da0e1f2f18 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h @@ -33,20 +33,28 @@ class TextureStorage9 : public TextureStorage D3DPOOL getPool() const; DWORD getUsage() const; - virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0; - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0; - virtual void generateMipmaps() = 0; + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture) = 0; + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT) = 0; virtual int getTopLevel() const; virtual bool isRenderTarget() const; virtual bool isManaged() const; virtual int getLevelCount() const; + virtual gl::Error setData(const gl::ImageIndex &index, Image *image, const gl::Box *destBox, GLenum type, + const gl::PixelUnpackState &unpack, const uint8_t *pixelData); + protected: int mTopLevel; + size_t mMipLevels; + size_t mTextureWidth; + size_t mTextureHeight; + GLenum mInternalFormat; + D3DFORMAT mTextureFormat; + Renderer9 *mRenderer; - TextureStorage9(Renderer *renderer, DWORD usage); + TextureStorage9(Renderer9 *renderer, DWORD usage); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage9); @@ -58,22 +66,21 @@ class TextureStorage9 : public TextureStorage class TextureStorage9_2D : public TextureStorage9 { public: - TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain); - TextureStorage9_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); + TextureStorage9_2D(Renderer9 *renderer, SwapChain9 *swapchain); + TextureStorage9_2D(Renderer9 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels); virtual ~TextureStorage9_2D(); static TextureStorage9_2D *makeTextureStorage9_2D(TextureStorage *storage); - IDirect3DSurface9 *getSurfaceLevel(int level, bool dirty); - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual IDirect3DBaseTexture9 *getBaseTexture() const; - virtual void generateMipmaps(); + gl::Error getSurfaceLevel(int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage9_2D); - void initializeRenderTarget(); - IDirect3DTexture9 *mTexture; RenderTarget9 *mRenderTarget; }; @@ -81,23 +88,24 @@ class TextureStorage9_2D : public TextureStorage9 class TextureStorage9_Cube : public TextureStorage9 { public: - TextureStorage9_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels); + TextureStorage9_Cube(Renderer9 *renderer, GLenum internalformat, bool renderTarget, int size, int levels); virtual ~TextureStorage9_Cube(); static TextureStorage9_Cube *makeTextureStorage9_Cube(TextureStorage *storage); - IDirect3DSurface9 *getCubeMapSurface(GLenum faceTarget, int level, bool dirty); - virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index); - virtual IDirect3DBaseTexture9 *getBaseTexture() const; - virtual void generateMipmaps(); + gl::Error getCubeMapSurface(GLenum faceTarget, int level, bool dirty, IDirect3DSurface9 **outSurface); + virtual gl::Error getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT); + virtual gl::Error getBaseTexture(IDirect3DBaseTexture9 **outTexture); + virtual gl::Error generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex); + virtual gl::Error copyToStorage(TextureStorage *destStorage); private: DISALLOW_COPY_AND_ASSIGN(TextureStorage9_Cube); - void initializeRenderTarget(); + static const size_t CUBE_FACE_COUNT = 6; IDirect3DCubeTexture9 *mTexture; - RenderTarget9 *mRenderTarget[6]; + RenderTarget9 *mRenderTarget[CUBE_FACE_COUNT]; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h index 66a6c64d81..791c108462 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexArray9.h @@ -19,7 +19,7 @@ class Renderer9; class VertexArray9 : public VertexArrayImpl { public: - VertexArray9(rx::Renderer9 *renderer) + VertexArray9(Renderer9 *renderer) : VertexArrayImpl(), mRenderer(renderer) { @@ -35,7 +35,7 @@ class VertexArray9 : public VertexArrayImpl private: DISALLOW_COPY_AND_ASSIGN(VertexArray9); - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; }; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp index 4cf7779118..b90133097c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp @@ -10,14 +10,14 @@ #include "libGLESv2/renderer/d3d/d3d9/Renderer9.h" #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" #include "libGLESv2/renderer/vertexconversion.h" -#include "libGLESv2/renderer/BufferImpl.h" +#include "libGLESv2/renderer/d3d/BufferD3D.h" #include "libGLESv2/VertexAttribute.h" #include "libGLESv2/Buffer.h" namespace rx { -VertexBuffer9::VertexBuffer9(rx::Renderer9 *renderer) : mRenderer(renderer) +VertexBuffer9::VertexBuffer9(Renderer9 *renderer) : mRenderer(renderer) { mVertexBuffer = NULL; mBufferSize = 0; @@ -97,8 +97,14 @@ gl::Error VertexBuffer9::storeVertexAttributes(const gl::VertexAttribute &attrib { if (buffer) { - BufferImpl *storage = buffer->getImplementation(); - input = static_cast(storage->getData()) + static_cast(attrib.offset); + BufferD3D *storage = BufferD3D::makeFromBuffer(buffer); + ASSERT(storage); + gl::Error error = storage->getData(&input); + if (error.isError()) + { + return error; + } + input += static_cast(attrib.offset); } else { @@ -203,7 +209,7 @@ gl::Error VertexBuffer9::spaceRequired(const gl::VertexAttribute &attrib, std::s else { // Round up to divisor, if possible - elementCount = rx::UnsignedCeilDivide(static_cast(instances), attrib.divisor); + elementCount = UnsignedCeilDivide(static_cast(instances), attrib.divisor); } if (d3d9VertexInfo.outputElementSize <= std::numeric_limits::max() / elementCount) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h index bdcf4bb64a..9af2b98a6e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.h @@ -18,7 +18,7 @@ class Renderer9; class VertexBuffer9 : public VertexBuffer { public: - explicit VertexBuffer9(rx::Renderer9 *renderer); + explicit VertexBuffer9(Renderer9 *renderer); virtual ~VertexBuffer9(); virtual gl::Error initialize(unsigned int size, bool dynamicUsage); @@ -39,7 +39,7 @@ class VertexBuffer9 : public VertexBuffer private: DISALLOW_COPY_AND_ASSIGN(VertexBuffer9); - rx::Renderer9 *mRenderer; + Renderer9 *mRenderer; IDirect3DVertexBuffer9 *mVertexBuffer; unsigned int mBufferSize; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp index e7a91e62d6..a98b2081f3 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp @@ -9,6 +9,7 @@ #include "libGLESv2/renderer/d3d/d3d9/renderer9_utils.h" #include "libGLESv2/renderer/d3d/d3d9/formatutils9.h" +#include "libGLESv2/renderer/Workarounds.h" #include "libGLESv2/formatutils.h" #include "libGLESv2/Framebuffer.h" #include "libGLESv2/renderer/d3d/d3d9/RenderTarget9.h" @@ -390,8 +391,9 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT caps->maxVertexUniformBlocks = 0; - const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 10; - const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 8; + // SM3 only supports 11 output variables, with a special 12th register for PSIZE. + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9; + const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7; caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; @@ -459,7 +461,7 @@ void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceT extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && - !(isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); + !(!isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); } else { @@ -531,10 +533,24 @@ void MakeValidSize(bool isImage, D3DFORMAT format, GLsizei *requestWidth, GLsize *levelOffset = upsampleCount; } -RenderTarget9 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment) +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget9 **outRT) { - RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment); - return RenderTarget9::makeRenderTarget9(renderTarget); + RenderTarget *renderTarget = NULL; + gl::Error error = rx::GetAttachmentRenderTarget(attachment, &renderTarget); + if (error.isError()) + { + return error; + } + *outRT = RenderTarget9::makeRenderTarget9(renderTarget); + return gl::Error(GL_NO_ERROR); +} + +Workarounds GenerateWorkarounds() +{ + Workarounds workarounds; + workarounds.mrtPerfWorkaround = true; + workarounds.setDataFasterThanImageUpload = false; + return workarounds; } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h index b0a940e60a..9760b9735a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.h @@ -12,6 +12,7 @@ #include "libGLESv2/angletypes.h" #include "libGLESv2/Caps.h" +#include "libGLESv2/Error.h" namespace gl { @@ -21,6 +22,7 @@ class FramebufferAttachment; namespace rx { class RenderTarget9; +struct Workarounds; namespace gl_d3d9 { @@ -74,7 +76,8 @@ inline bool isDeviceLostError(HRESULT errorCode) } } -RenderTarget9 *GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment); +gl::Error GetAttachmentRenderTarget(gl::FramebufferAttachment *attachment, RenderTarget9 **outRT); +Workarounds GenerateWorkarounds(); } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp index f777b30be6..159b4c7e9f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp @@ -10,10 +10,6 @@ #include "libGLESv2/renderer/loadimage.h" -#if !defined(__SSE2__) && (defined(_M_X64) || _M_IX86_FP == 2) -#define __SSE2__ -#endif - namespace rx { @@ -21,7 +17,12 @@ void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) { -#ifdef __SSE2__ +#if defined(_M_ARM) + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#else __m128i zeroWide = _mm_setzero_si128(); for (size_t z = 0; z < depth; z++) @@ -66,7 +67,12 @@ void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) { -#ifdef __SSE2__ +#if defined(_M_ARM) + // Ensure that this function is reported as not implemented for ARM builds because + // the instructions below are not present for that architecture. + UNIMPLEMENTED(); + return; +#else __m128i brMask = _mm_set1_epi32(0x00ff00ff); for (size_t z = 0; z < depth; z++) diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.cpp b/src/3rdparty/angle/src/libGLESv2/validationES.cpp index f79bc97e4f..265f4b4fba 100644 --- a/src/3rdparty/angle/src/libGLESv2/validationES.cpp +++ b/src/3rdparty/angle/src/libGLESv2/validationES.cpp @@ -24,6 +24,9 @@ #include "common/mathutil.h" #include "common/utilities.h" +// FIXME(jmadill): remove this when we support buffer data caching +#include "libGLESv2/renderer/d3d/BufferD3D.h" + namespace gl { @@ -497,14 +500,26 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer(); gl::Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer(); - if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE || - !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + + if (!readFramebuffer || !drawFramebuffer) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (drawFramebuffer->getSamples() != 0) + if (!readFramebuffer->completeness(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (!drawFramebuffer->completeness(context->getData())) + { + context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); + return false; + } + + if (drawFramebuffer->getSamples(context->getData()) != 0) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -588,16 +603,20 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint return false; } - if (attachment->getActualFormat() != readColorBuffer->getActualFormat()) + // Return an error if the destination formats do not match + if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat()) { context->recordError(Error(GL_INVALID_OPERATION)); return false; } } } - if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1)) + + int readSamples = readFramebuffer->getSamples(context->getData()); + + if (readSamples != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1)) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -912,13 +931,14 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); ASSERT(framebuffer); - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -1172,7 +1192,7 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, { Framebuffer *framebuffer = context->getState().getReadFramebuffer(); ASSERT(framebuffer); - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -1236,13 +1256,13 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi } gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples(context->getData()) != 0) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -1441,7 +1461,7 @@ static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsiz } const gl::Framebuffer *fbo = state.getDrawFramebuffer(); - if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; @@ -1667,11 +1687,20 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t // TODO: also disable index checking on back-ends that are robust to out-of-range accesses. if (elementArrayBuffer) { - GLint64 offset = reinterpret_cast(indices); + uintptr_t offset = reinterpret_cast(indices); if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL)) { - const void *dataPointer = elementArrayBuffer->getImplementation()->getData(); - const uint8_t *offsetPointer = static_cast(dataPointer) + offset; + // FIXME(jmadill): Use buffer data caching instead of the D3D back-end + rx::BufferD3D *bufferD3D = rx::BufferD3D::makeBufferD3D(elementArrayBuffer->getImplementation()); + const uint8_t *dataPointer = NULL; + Error error = bufferD3D->getData(&dataPointer); + if (error.isError()) + { + context->recordError(error); + return false; + } + + const uint8_t *offsetPointer = dataPointer + offset; *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count); } } @@ -1850,6 +1879,11 @@ bool ValidateGetUniformBase(Context *context, GLuint program, GLint location) return false; } + if (!ValidProgram(context, program)) + { + return false; + } + gl::Program *programObject = context->getProgram(program); if (!programObject || !programObject->isLinked()) diff --git a/src/3rdparty/angle/src/libGLESv2/validationES3.cpp b/src/3rdparty/angle/src/libGLESv2/validationES3.cpp index 251c6ad2c4..2d3a039e13 100644 --- a/src/3rdparty/angle/src/libGLESv2/validationES3.cpp +++ b/src/3rdparty/angle/src/libGLESv2/validationES3.cpp @@ -542,7 +542,8 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, return false; } - size_t copyBytes = widthSize * heightSize * depthSize * pixelBytes; + const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); + size_t copyBytes = formatInfo.computeBlockSize(type, width, height); size_t offset = reinterpret_cast(pixels); if (!rx::IsUnsignedAdditionSafe(offset, copyBytes) || @@ -555,12 +556,15 @@ bool ValidateES3TexImageParameters(Context *context, GLenum target, GLint level, // ...data is not evenly divisible into the number of bytes needed to store in memory a datum // indicated by type. - size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); - - if ((offset % dataBytesPerPixel) != 0) + if (!isCompressed) { - context->recordError(Error(GL_INVALID_OPERATION)); - return false; + size_t dataBytesPerPixel = static_cast(gl::GetTypeInfo(type).bytes); + + if ((offset % dataBytesPerPixel) != 0) + { + context->recordError(Error(GL_INVALID_OPERATION)); + return false; + } } // ...the buffer object's data store is currently mapped. @@ -872,13 +876,14 @@ bool ValidateES3CopyTexImageParameters(Context *context, GLenum target, GLint le gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer(); - if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (framebuffer->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; } - if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0) + if (context->getState().getReadFramebuffer()->id() != 0 && + framebuffer->getSamples(context->getData()) != 0) { context->recordError(Error(GL_INVALID_OPERATION)); return false; @@ -1258,7 +1263,7 @@ bool ValidateClearBuffer(Context *context) } const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer(); - if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE) + if (!fbo || fbo->completeness(context->getData()) != GL_FRAMEBUFFER_COMPLETE) { context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION)); return false; diff --git a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp index 19a9644d70..97dfcaac51 100644 --- a/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp +++ b/src/3rdparty/angle/src/third_party/systeminfo/SystemInfo.cpp @@ -24,6 +24,7 @@ */ #include +#include "common/platform.h" #if _WIN32_WINNT_WINBLUE #include @@ -52,7 +53,11 @@ bool isWindowsVistaOrGreater() if (!initialized) { initialized = true; +#if defined(ANGLE_ENABLE_WINDOWS_STORE) + cachedIsWindowsVistaOrGreater = true; +#else cachedIsWindowsVistaOrGreater = IsWindowsVistaOrGreater(); +#endif } return cachedIsWindowsVistaOrGreater; } diff --git a/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch b/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch index d5e3697c4f..ad3187ec7c 100644 --- a/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch +++ b/src/angle/patches/0000-General-fixes-for-ANGLE-2.1.patch @@ -1,178 +1,49 @@ -From f409f6837ce80d722eb6d2ff178b61b713d3e8c7 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Thu, 25 Sep 2014 13:23:19 +0300 +From bd27c33a4a7c48bd14b9b6c18c8cdce1c3aae155 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Fri, 14 Nov 2014 10:53:40 +0200 Subject: [PATCH] General fixes for ANGLE 2.1 - Fix commit.h include (use hard-coded version) -- Fix undefined intptr_t in egl.h and eglext.h - Fix export mismatch in libEGL.cpp and libGLESv2.cpp -- Remove D3D9 d3dcompiler.h include requirement in the translator - Normalize all precompiled shader names and includes - Remove third-party event tracing; it was hardly used in ANGLE and not enabled in Qt builds anyway. Change-Id: I22254aed62e89a26756ca0784bae95909189c0f9 --- - src/3rdparty/angle/include/EGL/egl.h | 2 +- - src/3rdparty/angle/include/EGL/eglext.h | 2 +- - src/3rdparty/angle/src/common/event_tracer.cpp | 49 -- - src/3rdparty/angle/src/common/event_tracer.h | 43 -- - src/3rdparty/angle/src/common/version.h | 2 +- - src/3rdparty/angle/src/libEGL/libEGL.cpp | 3 + - src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 5 + - src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 3 - - .../angle/src/libGLESv2/libGLESv2_mingw32.def | 3 - - src/3rdparty/angle/src/libGLESv2/libGLESv2d.def | 3 - - .../angle/src/libGLESv2/libGLESv2d_mingw32.def | 3 - - .../angle/src/libGLESv2/renderer/Renderer.cpp | 1 - - .../angle/src/libGLESv2/renderer/SwapChain.h | 4 - - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 6 +- - .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 66 +- - .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 12 +- - .../renderer/d3d/d3d11/PixelTransfer11.cpp | 10 +- - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 4 +- - .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 4 + - .../src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp | 20 +- - .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 12 - - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps | 6 +- - .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs | 4 +- - .../src/third_party/trace_event/trace_event.h | 826 --------------------- - src/angle/src/common/common.pri | 2 - - 25 files changed, 80 insertions(+), 1015 deletions(-) - delete mode 100644 src/3rdparty/angle/src/common/event_tracer.cpp - delete mode 100644 src/3rdparty/angle/src/common/event_tracer.h - delete mode 100644 src/3rdparty/angle/src/third_party/trace_event/trace_event.h + src/3rdparty/angle/src/commit.h | 6 +- + src/3rdparty/angle/src/common/version.h | 2 +- + .../src/common/winrt/CoreWindowNativeWindow.cpp | 2 +- + src/3rdparty/angle/src/libEGL/libEGL.cpp | 3 + + src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp | 4 ++ + src/3rdparty/angle/src/libGLESv2/libGLESv2.def | 3 - + .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 3 - + .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 66 +++++++++++----------- + .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 12 ++-- + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 10 ++-- + .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 4 +- + .../renderer/d3d/d3d11/shaders/Clear11.hlsl | 4 ++ + .../src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp | 20 +++---- + .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 12 ---- + .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.ps | 6 +- + .../libGLESv2/renderer/d3d/d3d9/shaders/Blit.vs | 4 +- + 16 files changed, 76 insertions(+), 85 deletions(-) -diff --git a/src/3rdparty/angle/include/EGL/egl.h b/src/3rdparty/angle/include/EGL/egl.h -index 12590a0..ab2f0cd 100644 ---- a/src/3rdparty/angle/include/EGL/egl.h -+++ b/src/3rdparty/angle/include/EGL/egl.h -@@ -238,7 +238,7 @@ EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void); - #ifndef EGL_VERSION_1_5 - #define EGL_VERSION_1_5 1 - typedef void *EGLSync; --typedef intptr_t EGLAttrib; -+typedef khronos_intptr_t EGLAttrib; - typedef khronos_utime_nanoseconds_t EGLTime; - #define EGL_CONTEXT_MAJOR_VERSION 0x3098 - #define EGL_CONTEXT_MINOR_VERSION 0x30FB -diff --git a/src/3rdparty/angle/include/EGL/eglext.h b/src/3rdparty/angle/include/EGL/eglext.h -index 9e29605..989359b 100644 ---- a/src/3rdparty/angle/include/EGL/eglext.h -+++ b/src/3rdparty/angle/include/EGL/eglext.h -@@ -59,7 +59,7 @@ extern "C" { - #ifndef EGL_KHR_cl_event2 - #define EGL_KHR_cl_event2 1 - typedef void *EGLSyncKHR; --typedef intptr_t EGLAttribKHR; -+typedef khronos_intptr_t EGLAttribKHR; - typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list); - #ifdef EGL_EGLEXT_PROTOTYPES - EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list); -diff --git a/src/3rdparty/angle/src/common/event_tracer.cpp b/src/3rdparty/angle/src/common/event_tracer.cpp -deleted file mode 100644 -index 353c69d..0000000 ---- a/src/3rdparty/angle/src/common/event_tracer.cpp -+++ /dev/null -@@ -1,49 +0,0 @@ --// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. --// Use of this source code is governed by a BSD-style license that can be --// found in the LICENSE file. +diff --git a/src/3rdparty/angle/src/commit.h b/src/3rdparty/angle/src/commit.h +index 4c89a65..08fc893 100644 +--- a/src/3rdparty/angle/src/commit.h ++++ b/src/3rdparty/angle/src/commit.h +@@ -7,8 +7,6 @@ + // This is a default commit hash header, when git is not available. + // + +-#define ANGLE_COMMIT_HASH "unknown hash" ++#define ANGLE_COMMIT_HASH "30d6c255d238" + #define ANGLE_COMMIT_HASH_SIZE 12 +-#define ANGLE_COMMIT_DATE "unknown date" - --#include "common/event_tracer.h" -- --namespace gl --{ -- --GetCategoryEnabledFlagFunc g_getCategoryEnabledFlag; --AddTraceEventFunc g_addTraceEvent; -- --} // namespace gl -- --extern "C" { -- --void TRACE_ENTRY SetTraceFunctionPointers(GetCategoryEnabledFlagFunc getCategoryEnabledFlag, -- AddTraceEventFunc addTraceEvent) --{ -- gl::g_getCategoryEnabledFlag = getCategoryEnabledFlag; -- gl::g_addTraceEvent = addTraceEvent; --} -- --} // extern "C" -- --namespace gl --{ -- --const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name) --{ -- if (g_getCategoryEnabledFlag) -- { -- return g_getCategoryEnabledFlag(name); -- } -- static unsigned char disabled = 0; -- return &disabled; --} -- --void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id, -- int numArgs, const char** argNames, const unsigned char* argTypes, -- const unsigned long long* argValues, unsigned char flags) --{ -- if (g_addTraceEvent) -- { -- g_addTraceEvent(phase, categoryGroupEnabled, name, id, numArgs, argNames, argTypes, argValues, flags); -- } --} -- --} // namespace gl -diff --git a/src/3rdparty/angle/src/common/event_tracer.h b/src/3rdparty/angle/src/common/event_tracer.h -deleted file mode 100644 -index fa97435..0000000 ---- a/src/3rdparty/angle/src/common/event_tracer.h -+++ /dev/null -@@ -1,43 +0,0 @@ --// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved. --// Use of this source code is governed by a BSD-style license that can be --// found in the LICENSE file. -- --#ifndef COMMON_EVENT_TRACER_H_ --#define COMMON_EVENT_TRACER_H_ -- --#include "common/platform.h" -- --#if !defined(TRACE_ENTRY) --# ifdef ANGLE_PLATFORM_WINDOWS --# define TRACE_ENTRY __stdcall --# else --# define TRACE_ENTRY --# endif // ANGLE_PLATFORM_WINDOWS --#endif //TRACE_ENTRY -- --extern "C" { -- --typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name); --typedef void (*AddTraceEventFunc)(char phase, const unsigned char* categoryGroupEnabled, const char* name, -- unsigned long long id, int numArgs, const char** argNames, -- const unsigned char* argTypes, const unsigned long long* argValues, -- unsigned char flags); -- --// extern "C" so that it has a reasonable name for GetProcAddress. --void TRACE_ENTRY SetTraceFunctionPointers(GetCategoryEnabledFlagFunc get_category_enabled_flag, -- AddTraceEventFunc add_trace_event_func); -- --} -- --namespace gl --{ -- --const unsigned char* TraceGetTraceCategoryEnabledFlag(const char* name); -- --void TraceAddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id, -- int numArgs, const char** argNames, const unsigned char* argTypes, -- const unsigned long long* argValues, unsigned char flags); -- --} -- --#endif // COMMON_EVENT_TRACER_H_ +-#define ANGLE_DISABLE_PROGRAM_BINARY_LOAD ++#define ANGLE_COMMIT_DATE "2014-11-13 17:37:03 +0000" diff --git a/src/3rdparty/angle/src/common/version.h b/src/3rdparty/angle/src/common/version.h index d9148d1..f01e024 100644 --- a/src/3rdparty/angle/src/common/version.h @@ -183,8 +54,19 @@ index d9148d1..f01e024 100644 #define ANGLE_MAJOR_VERSION 2 #define ANGLE_MINOR_VERSION 1 +diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp +index 0de16f4..0e63fa5 100644 +--- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp +@@ -184,4 +184,4 @@ long ConvertDipsToPixels(float dips) + static const float dipsPerInch = 96.0f; + return lround((dips * GetLogicalDpi() / dipsPerInch)); + } +-} +\ No newline at end of file ++} diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index f9a4780..7ce2b93 100644 +index 851b723..6110698 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.cpp +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp @@ -6,6 +6,9 @@ @@ -198,7 +80,7 @@ index f9a4780..7ce2b93 100644 #include "common/debug.h" diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp -index 198c0ee..07f5d47 100644 +index 2306168..587950a 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp +++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2.cpp @@ -6,6 +6,10 @@ @@ -212,14 +94,6 @@ index 198c0ee..07f5d47 100644 #include "common/version.h" #include "common/utilities.h" -@@ -30,6 +34,7 @@ - #include "libGLESv2/validationES3.h" - #include "libGLESv2/queryconversions.h" - -+ - extern "C" - { - diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2.def index 88dceb3..33557eb 100644 --- a/src/3rdparty/angle/src/libGLESv2/libGLESv2.def @@ -231,93 +105,29 @@ index 88dceb3..33557eb 100644 - - ; Setting up TRACE macro callbacks - SetTraceFunctionPointers @284 -diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def -index d6272c4d..18ffcf6 100644 ---- a/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def -+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2_mingw32.def -@@ -294,6 +294,3 @@ EXPORTS - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME -- -- ; Setting up TRACE macro callbacks -- SetTraceFunctionPointers@8 @284 -diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def -index d301aa0..120371e 100644 ---- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def -+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d.def -@@ -294,6 +294,3 @@ EXPORTS - glBindTexImage @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME -- -- ; Setting up TRACE macro callbacks -- SetTraceFunctionPointers @284 -diff --git a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def -index a82d629..8c1306a 100644 ---- a/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def -+++ b/src/3rdparty/angle/src/libGLESv2/libGLESv2d_mingw32.def -@@ -294,6 +294,3 @@ EXPORTS - glBindTexImage@4 @158 NONAME - glCreateRenderer @177 NONAME - glDestroyRenderer @178 NONAME -- -- ; Setting up TRACE macro callbacks -- SetTraceFunctionPointers@8 @284 -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp -index df43012..910d028 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.cpp -@@ -10,7 +10,6 @@ - #include "libGLESv2/Program.h" - #include "libGLESv2/renderer/Renderer.h" - #include "common/utilities.h" --#include "third_party/trace_event/trace_event.h" - #include "libGLESv2/Shader.h" - - #if defined (ANGLE_ENABLE_D3D9) -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -index c53b2af..12be9b3 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -@@ -16,10 +16,6 @@ - #include - #include - --#if !defined(ANGLE_FORCE_VSYNC_OFF) --#define ANGLE_FORCE_VSYNC_OFF 0 --#endif -- - namespace rx - { - diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index df2e46c..acbd852 100644 +index 5c44fe0..bfeaf51 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -10,8 +10,6 @@ - +@@ -11,8 +11,6 @@ + #include "common/features.h" #include "common/utilities.h" -#include "third_party/trace_event/trace_event.h" - - namespace rx + // Definitions local to the translation unit + namespace { - -@@ -28,7 +26,11 @@ HLSLCompiler::~HLSLCompiler() +@@ -120,7 +118,6 @@ HLSLCompiler::~HLSLCompiler() bool HLSLCompiler::initialize() { -+<<<<<<< HEAD - TRACE_EVENT0("gpu", "initializeCompiler"); -+======= -+#if !defined(ANGLE_PLATFORM_WINRT) -+>>>>>>> 429814a... ANGLE: remove event tracing +- TRACE_EVENT0("gpu", "initializeCompiler"); + #if !defined(ANGLE_ENABLE_WINDOWS_STORE) #if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. - static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -index 3bdb9e7..72820a4 100644 +index 8ed1650..91e7552 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp @@ -13,39 +13,39 @@ @@ -394,7 +204,7 @@ index 3bdb9e7..72820a4 100644 #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlef2dps.h" #include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/swizzlei2dps.h" diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -index c60b7a6..5caa427 100644 +index 12905d0..4630762 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp @@ -15,14 +15,14 @@ @@ -419,7 +229,7 @@ index c60b7a6..5caa427 100644 namespace rx { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -index f54bacc..edaafec 100644 +index 1bc2bd8..a4072d8 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp @@ -22,11 +22,11 @@ @@ -440,7 +250,7 @@ index f54bacc..edaafec 100644 namespace rx { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -index 5ec132e..50dae4e 100644 +index 3fcacf6..834b7bd 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp @@ -12,8 +12,8 @@ @@ -452,8 +262,8 @@ index 5ec132e..50dae4e 100644 +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthrough2dvs.h" +#include "libGLESv2/renderer/d3d/d3d11/shaders/compiled/passthroughrgba2dps.h" - namespace rx - { + #include "common/features.h" + #include "common/NativeWindow.h" diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl index 6deef2b..b4cf380 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/shaders/Clear11.hlsl @@ -485,7 +295,7 @@ index 6deef2b..b4cf380 100644 } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp -index 80503d5..f061a32 100644 +index d4fcd17..2ca7a9c 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp @@ -27,20 +27,20 @@ namespace @@ -520,11 +330,11 @@ index 80503d5..f061a32 100644 } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 73c1abc..e8564bd 100644 +index 3bac4ba..82963ec 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -39,8 +39,6 @@ - +@@ -42,8 +42,6 @@ + #include "common/features.h" #include "common/utilities.h" -#include "third_party/trace_event/trace_event.h" @@ -532,7 +342,7 @@ index 73c1abc..e8564bd 100644 #include // Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros -@@ -190,7 +188,6 @@ EGLint Renderer9::initialize() +@@ -185,7 +183,6 @@ EGLint Renderer9::initialize() return EGL_NOT_INITIALIZED; } @@ -540,9 +350,9 @@ index 73c1abc..e8564bd 100644 mD3d9Module = GetModuleHandle(TEXT("d3d9.dll")); if (mD3d9Module == NULL) -@@ -207,14 +204,12 @@ EGLint Renderer9::initialize() +@@ -202,14 +199,12 @@ EGLint Renderer9::initialize() // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available. - if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) + if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) { - TRACE_EVENT0("gpu", "D3d9Ex_QueryInterface"); ASSERT(mD3d9Ex); @@ -555,7 +365,7 @@ index 73c1abc..e8564bd 100644 mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); } -@@ -233,7 +228,6 @@ EGLint Renderer9::initialize() +@@ -228,7 +223,6 @@ EGLint Renderer9::initialize() // Give up on getting device caps after about one second. { @@ -563,7 +373,7 @@ index 73c1abc..e8564bd 100644 for (int i = 0; i < 10; ++i) { result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps); -@@ -268,7 +262,6 @@ EGLint Renderer9::initialize() +@@ -263,7 +257,6 @@ EGLint Renderer9::initialize() } { @@ -571,7 +381,7 @@ index 73c1abc..e8564bd 100644 mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier); } -@@ -305,7 +298,6 @@ EGLint Renderer9::initialize() +@@ -300,7 +293,6 @@ EGLint Renderer9::initialize() static const TCHAR className[] = TEXT("STATIC"); { @@ -579,7 +389,7 @@ index 73c1abc..e8564bd 100644 mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL); } -@@ -313,7 +305,6 @@ EGLint Renderer9::initialize() +@@ -308,7 +300,6 @@ EGLint Renderer9::initialize() DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; { @@ -587,7 +397,7 @@ index 73c1abc..e8564bd 100644 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); } if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST) -@@ -323,7 +314,6 @@ EGLint Renderer9::initialize() +@@ -318,7 +309,6 @@ EGLint Renderer9::initialize() if (FAILED(result)) { @@ -595,7 +405,7 @@ index 73c1abc..e8564bd 100644 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice); if (FAILED(result)) -@@ -335,13 +325,11 @@ EGLint Renderer9::initialize() +@@ -330,13 +320,11 @@ EGLint Renderer9::initialize() if (mD3d9Ex) { @@ -662,858 +472,6 @@ index 3a36980..3bd611b 100644 { VS_OUTPUT Out; -diff --git a/src/3rdparty/angle/src/third_party/trace_event/trace_event.h b/src/3rdparty/angle/src/third_party/trace_event/trace_event.h -deleted file mode 100644 -index 1880056..0000000 ---- a/src/3rdparty/angle/src/third_party/trace_event/trace_event.h -+++ /dev/null -@@ -1,826 +0,0 @@ --// Copyright (c) 2013 The Chromium Authors. All rights reserved. --// Use of this source code is governed by a BSD-style license that can be --// found in the LICENSE file. -- --// Trace events are for tracking application performance and resource usage. --// Macros are provided to track: --// Begin and end of function calls --// Counters --// --// Events are issued against categories. Whereas LOG's --// categories are statically defined, TRACE categories are created --// implicitly with a string. For example: --// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent") --// --// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope: --// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly") --// doSomethingCostly() --// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly") --// Note: our tools can't always determine the correct BEGIN/END pairs unless --// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you need them --// to be in separate scopes. --// --// A common use case is to trace entire function scopes. This --// issues a trace BEGIN and END automatically: --// void doSomethingCostly() { --// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly"); --// ... --// } --// --// Additional parameters can be associated with an event: --// void doSomethingCostly2(int howMuch) { --// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly", --// "howMuch", howMuch); --// ... --// } --// --// The trace system will automatically add to this information the --// current process id, thread id, and a timestamp in microseconds. --// --// To trace an asynchronous procedure such as an IPC send/receive, use ASYNC_BEGIN and --// ASYNC_END: --// [single threaded sender code] --// static int send_count = 0; --// ++send_count; --// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count); --// Send(new MyMessage(send_count)); --// [receive code] --// void OnMyMessage(send_count) { --// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count); --// } --// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs. --// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process. Pointers can --// be used for the ID parameter, and they will be mangled internally so that --// the same pointer on two different processes will not match. For example: --// class MyTracedClass { --// public: --// MyTracedClass() { --// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this); --// } --// ~MyTracedClass() { --// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this); --// } --// } --// --// Trace event also supports counters, which is a way to track a quantity --// as it varies over time. Counters are created with the following macro: --// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue); --// --// Counters are process-specific. The macro itself can be issued from any --// thread, however. --// --// Sometimes, you want to track two counters at once. You can do this with two --// counter macros: --// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]); --// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]); --// Or you can do it with a combined macro: --// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter", --// "bytesPinned", g_myCounterValue[0], --// "bytesAllocated", g_myCounterValue[1]); --// This indicates to the tracing UI that these counters should be displayed --// in a single graph, as a summed area chart. --// --// Since counters are in a global namespace, you may want to disembiguate with a --// unique ID, by using the TRACE_COUNTER_ID* variations. --// --// By default, trace collection is compiled in, but turned off at runtime. --// Collecting trace data is the responsibility of the embedding --// application. In Chrome's case, navigating to about:tracing will turn on --// tracing and display data collected across all active processes. --// --// --// Memory scoping note: --// Tracing copies the pointers, not the string content, of the strings passed --// in for category, name, and arg_names. Thus, the following code will --// cause problems: --// char* str = strdup("impprtantName"); --// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD! --// free(str); // Trace system now has dangling pointer --// --// To avoid this issue with the |name| and |arg_name| parameters, use the --// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead. --// Notes: The category must always be in a long-lived char* (i.e. static const). --// The |arg_values|, when used, are always deep copied with the _COPY --// macros. --// --// When are string argument values copied: --// const char* arg_values are only referenced by default: --// TRACE_EVENT1("category", "name", --// "arg1", "literal string is only referenced"); --// Use TRACE_STR_COPY to force copying of a const char*: --// TRACE_EVENT1("category", "name", --// "arg1", TRACE_STR_COPY("string will be copied")); --// std::string arg_values are always copied: --// TRACE_EVENT1("category", "name", --// "arg1", std::string("string will be copied")); --// --// --// Thread Safety: --// A thread safe singleton and mutex are used for thread safety. Category --// enabled flags are used to limit the performance impact when the system --// is not enabled. --// --// TRACE_EVENT macros first cache a pointer to a category. The categories are --// statically allocated and safe at all times, even after exit. Fetching a --// category is protected by the TraceLog::lock_. Multiple threads initializing --// the static variable is safe, as they will be serialized by the lock and --// multiple calls will return the same pointer to the category. --// --// Then the category_enabled flag is checked. This is a unsigned char, and --// not intended to be multithread safe. It optimizes access to addTraceEvent --// which is threadsafe internally via TraceLog::lock_. The enabled flag may --// cause some threads to incorrectly call or skip calling addTraceEvent near --// the time of the system being enabled or disabled. This is acceptable as --// we tolerate some data loss while the system is being enabled/disabled and --// because addTraceEvent is threadsafe internally and checks the enabled state --// again under lock. --// --// Without the use of these static category pointers and enabled flags all --// trace points would carry a significant performance cost of aquiring a lock --// and resolving the category. -- --#ifndef COMMON_TRACE_EVENT_H_ --#define COMMON_TRACE_EVENT_H_ -- --#include -- --#include "common/event_tracer.h" -- --// By default, const char* argument values are assumed to have long-lived scope --// and will not be copied. Use this macro to force a const char* to be copied. --#define TRACE_STR_COPY(str) \ -- WebCore::TraceEvent::TraceStringWithCopy(str) -- --// Records a pair of begin and end events called "name" for the current --// scope, with 0, 1 or 2 associated arguments. If the category is not --// enabled, then this does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_EVENT0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name) --#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val) --#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) -- --// Records a single event called "name" immediately, with 0, 1 or 2 --// associated arguments. If the category is not enabled, then this --// does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_EVENT_INSTANT0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) --#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ -- arg2_name, arg2_val) --#define TRACE_EVENT_COPY_INSTANT0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) --#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ -- arg2_name, arg2_val) -- --// Records a single BEGIN event called "name" immediately, with 0, 1 or 2 --// associated arguments. If the category is not enabled, then this --// does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_EVENT_BEGIN0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) --#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ -- arg2_name, arg2_val) --#define TRACE_EVENT_COPY_BEGIN0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) --#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ -- arg2_name, arg2_val) -- --// Records a single END event for "name" immediately. If the category --// is not enabled, then this does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_EVENT_END0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) --#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \ -- arg2_name, arg2_val) --#define TRACE_EVENT_COPY_END0(category, name) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val) --#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \ -- category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \ -- arg2_name, arg2_val) -- --// Records the value of a counter called "name" immediately. Value --// must be representable as a 32 bit integer. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_COUNTER1(category, name, value) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, TRACE_EVENT_FLAG_NONE, \ -- "value", static_cast(value)) --#define TRACE_COPY_COUNTER1(category, name, value) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, TRACE_EVENT_FLAG_COPY, \ -- "value", static_cast(value)) -- --// Records the values of a multi-parted counter called "name" immediately. --// The UI will treat value1 and value2 as parts of a whole, displaying their --// values as a stacked-bar chart. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --#define TRACE_COUNTER2(category, name, value1_name, value1_val, \ -- value2_name, value2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, TRACE_EVENT_FLAG_NONE, \ -- value1_name, static_cast(value1_val), \ -- value2_name, static_cast(value2_val)) --#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \ -- value2_name, value2_val) \ -- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, TRACE_EVENT_FLAG_COPY, \ -- value1_name, static_cast(value1_val), \ -- value2_name, static_cast(value2_val)) -- --// Records the value of a counter called "name" immediately. Value --// must be representable as a 32 bit integer. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --// - |id| is used to disambiguate counters with the same name. It must either --// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits --// will be xored with a hash of the process ID so that the same pointer on --// two different processes will not collide. --#define TRACE_COUNTER_ID1(category, name, id, value) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, \ -- "value", static_cast(value)) --#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- "value", static_cast(value)) -- --// Records the values of a multi-parted counter called "name" immediately. --// The UI will treat value1 and value2 as parts of a whole, displaying their --// values as a stacked-bar chart. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --// - |id| is used to disambiguate counters with the same name. It must either --// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits --// will be xored with a hash of the process ID so that the same pointer on --// two different processes will not collide. --#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \ -- value2_name, value2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, \ -- value1_name, static_cast(value1_val), \ -- value2_name, static_cast(value2_val)) --#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \ -- value2_name, value2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- value1_name, static_cast(value1_val), \ -- value2_name, static_cast(value2_val)) -- --// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2 --// associated arguments. If the category is not enabled, then this --// does nothing. --// - category and name strings must have application lifetime (statics or --// literals). They may not include " chars. --// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC --// events are considered to match if their category, name and id values all --// match. |id| must either be a pointer or an integer value up to 64 bits. If --// it's a pointer, the bits will be xored with a hash of the process ID so --// that the same pointer on two different processes will not collide. --// An asynchronous operation can consist of multiple phases. The first phase is --// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the --// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END. --// An async operation can span threads and processes, but all events in that --// operation must use the same |name| and |id|. Each event can have its own --// args. --#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) --#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, \ -- arg1_name, arg1_val, arg2_name, arg2_val) --#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- arg1_name, arg1_val) --#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- arg1_name, arg1_val, arg2_name, arg2_val) -- --// Records a single ASYNC_STEP event for |step| immediately. If the category --// is not enabled, then this does nothing. The |name| and |id| must match the --// ASYNC_BEGIN event above. The |step| param identifies this step within the --// async event. This should be called at the beginning of the next phase of an --// asynchronous operation. --#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, "step", step) --#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \ -- arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \ -- arg1_name, arg1_val) --#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, "step", step) --#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \ -- arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \ -- arg1_name, arg1_val) -- --// Records a single ASYNC_END event for "name" immediately. If the category --// is not enabled, then this does nothing. --#define TRACE_EVENT_ASYNC_END0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_NONE) --#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val) --#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_NONE, \ -- arg1_name, arg1_val, arg2_name, arg2_val) --#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_COPY) --#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- arg1_name, arg1_val) --#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \ -- arg2_name, arg2_val) \ -- INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \ -- category, name, id, TRACE_EVENT_FLAG_COPY, \ -- arg1_name, arg1_val, arg2_name, arg2_val) -- --// Creates a scope of a sampling state with the given category and name (both must --// be constant strings). These states are intended for a sampling profiler. --// Implementation note: we store category and name together because we don't --// want the inconsistency/expense of storing two pointers. --// |thread_bucket| is [0..2] and is used to statically isolate samples in one --// thread from others. --// --// { // The sampling state is set within this scope. --// TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name"); --// ...; --// } --#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, name) \ -- TraceEvent::SamplingStateScope traceEventSamplingScope(category "\0" name); -- --// Returns a current sampling state of the given bucket. --// The format of the returned string is "category\0name". --#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \ -- TraceEvent::SamplingStateScope::current() -- --// Sets a current sampling state of the given bucket. --// |category| and |name| have to be constant strings. --#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(bucket_number, category, name) \ -- TraceEvent::SamplingStateScope::set(category "\0" name) -- --// Sets a current sampling state of the given bucket. --// |categoryAndName| doesn't need to be a constant string. --// The format of the string is "category\0name". --#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(bucket_number, categoryAndName) \ -- TraceEvent::SamplingStateScope::set(categoryAndName) -- --// Syntactic sugars for the sampling tracing in the main thread. --#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \ -- TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name) --#define TRACE_EVENT_GET_SAMPLING_STATE() \ -- TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0) --#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \ -- TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name) --#define TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(categoryAndName) \ -- TRACE_EVENT_SET_NONCONST_SAMPLING_STATE_FOR_BUCKET(0, categoryAndName) -- --//////////////////////////////////////////////////////////////////////////////// --// Implementation specific tracing API definitions. -- --// Get a pointer to the enabled state of the given trace category. Only --// long-lived literal strings should be given as the category name. The returned --// pointer can be held permanently in a local static for example. If the --// unsigned char is non-zero, tracing is enabled. If tracing is enabled, --// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled --// between the load of the tracing state and the call to --// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out --// for best performance when tracing is disabled. --// const unsigned char* --// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name) --#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \ -- gl::TraceGetTraceCategoryEnabledFlag -- --// Add a trace event to the platform tracing system. --// void TRACE_EVENT_API_ADD_TRACE_EVENT( --// char phase, --// const unsigned char* category_enabled, --// const char* name, --// unsigned long long id, --// int num_args, --// const char** arg_names, --// const unsigned char* arg_types, --// const unsigned long long* arg_values, --// unsigned char flags) --#define TRACE_EVENT_API_ADD_TRACE_EVENT \ -- gl::TraceAddTraceEvent -- --//////////////////////////////////////////////////////////////////////////////// -- --// Implementation detail: trace event macros create temporary variables --// to keep instrumentation overhead low. These macros give each temporary --// variable a unique name based on the line number to prevent name collissions. --#define INTERNAL_TRACE_EVENT_UID3(a, b) \ -- trace_event_unique_##a##b --#define INTERNAL_TRACE_EVENT_UID2(a, b) \ -- INTERNAL_TRACE_EVENT_UID3(a, b) --#define INTERNALTRACEEVENTUID(name_prefix) \ -- INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__) -- --// Implementation detail: internal macro to create static category. --#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \ -- static const unsigned char* INTERNALTRACEEVENTUID(catstatic) = 0; \ -- if (!INTERNALTRACEEVENTUID(catstatic)) \ -- INTERNALTRACEEVENTUID(catstatic) = \ -- TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); -- --// Implementation detail: internal macro to create static category and add --// event if the category is enabled. --#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \ -- do { \ -- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ -- if (*INTERNALTRACEEVENTUID(catstatic)) { \ -- gl::TraceEvent::addTraceEvent( \ -- phase, INTERNALTRACEEVENTUID(catstatic), name, \ -- gl::TraceEvent::noEventId, flags, ##__VA_ARGS__); \ -- } \ -- } while (0) -- --// Implementation detail: internal macro to create static category and add begin --// event if the category is enabled. Also adds the end event when the scope --// ends. --#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \ -- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ -- gl::TraceEvent::TraceEndOnScopeClose \ -- INTERNALTRACEEVENTUID(profileScope); \ -- if (*INTERNALTRACEEVENTUID(catstatic)) { \ -- gl::TraceEvent::addTraceEvent( \ -- TRACE_EVENT_PHASE_BEGIN, \ -- INTERNALTRACEEVENTUID(catstatic), \ -- name, gl::TraceEvent::noEventId, \ -- TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \ -- INTERNALTRACEEVENTUID(profileScope).initialize( \ -- INTERNALTRACEEVENTUID(catstatic), name); \ -- } -- --// Implementation detail: internal macro to create static category and add --// event if the category is enabled. --#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \ -- ...) \ -- do { \ -- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ -- if (*INTERNALTRACEEVENTUID(catstatic)) { \ -- unsigned char traceEventFlags = flags | TRACE_EVENT_FLAG_HAS_ID; \ -- gl::TraceEvent::TraceID traceEventTraceID( \ -- id, &traceEventFlags); \ -- gl::TraceEvent::addTraceEvent( \ -- phase, INTERNALTRACEEVENTUID(catstatic), \ -- name, traceEventTraceID.data(), traceEventFlags, \ -- ##__VA_ARGS__); \ -- } \ -- } while (0) -- --// Notes regarding the following definitions: --// New values can be added and propagated to third party libraries, but existing --// definitions must never be changed, because third party libraries may use old --// definitions. -- --// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. --#define TRACE_EVENT_PHASE_BEGIN ('B') --#define TRACE_EVENT_PHASE_END ('E') --#define TRACE_EVENT_PHASE_INSTANT ('I') --#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') --#define TRACE_EVENT_PHASE_ASYNC_STEP ('T') --#define TRACE_EVENT_PHASE_ASYNC_END ('F') --#define TRACE_EVENT_PHASE_METADATA ('M') --#define TRACE_EVENT_PHASE_COUNTER ('C') --#define TRACE_EVENT_PHASE_SAMPLE ('P') -- --// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT. --#define TRACE_EVENT_FLAG_NONE (static_cast(0)) --#define TRACE_EVENT_FLAG_COPY (static_cast(1 << 0)) --#define TRACE_EVENT_FLAG_HAS_ID (static_cast(1 << 1)) --#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast(1 << 2)) -- --// Type values for identifying types in the TraceValue union. --#define TRACE_VALUE_TYPE_BOOL (static_cast(1)) --#define TRACE_VALUE_TYPE_UINT (static_cast(2)) --#define TRACE_VALUE_TYPE_INT (static_cast(3)) --#define TRACE_VALUE_TYPE_DOUBLE (static_cast(4)) --#define TRACE_VALUE_TYPE_POINTER (static_cast(5)) --#define TRACE_VALUE_TYPE_STRING (static_cast(6)) --#define TRACE_VALUE_TYPE_COPY_STRING (static_cast(7)) -- -- --namespace gl { -- --namespace TraceEvent { -- --// Specify these values when the corresponding argument of addTraceEvent is not --// used. --const int zeroNumArgs = 0; --const unsigned long long noEventId = 0; -- --// TraceID encapsulates an ID that can either be an integer or pointer. Pointers --// are mangled with the Process ID so that they are unlikely to collide when the --// same pointer is used on different processes. --class TraceID { --public: -- explicit TraceID(const void* id, unsigned char* flags) : -- m_data(static_cast(reinterpret_cast(id))) -- { -- *flags |= TRACE_EVENT_FLAG_MANGLE_ID; -- } -- explicit TraceID(unsigned long long id, unsigned char* flags) : m_data(id) { (void)flags; } -- explicit TraceID(unsigned long id, unsigned char* flags) : m_data(id) { (void)flags; } -- explicit TraceID(unsigned int id, unsigned char* flags) : m_data(id) { (void)flags; } -- explicit TraceID(unsigned short id, unsigned char* flags) : m_data(id) { (void)flags; } -- explicit TraceID(unsigned char id, unsigned char* flags) : m_data(id) { (void)flags; } -- explicit TraceID(long long id, unsigned char* flags) : -- m_data(static_cast(id)) { (void)flags; } -- explicit TraceID(long id, unsigned char* flags) : -- m_data(static_cast(id)) { (void)flags; } -- explicit TraceID(int id, unsigned char* flags) : -- m_data(static_cast(id)) { (void)flags; } -- explicit TraceID(short id, unsigned char* flags) : -- m_data(static_cast(id)) { (void)flags; } -- explicit TraceID(signed char id, unsigned char* flags) : -- m_data(static_cast(id)) { (void)flags; } -- -- unsigned long long data() const { return m_data; } -- --private: -- unsigned long long m_data; --}; -- --// Simple union to store various types as unsigned long long. --union TraceValueUnion { -- bool m_bool; -- unsigned long long m_uint; -- long long m_int; -- double m_double; -- const void* m_pointer; -- const char* m_string; --}; -- --// Simple container for const char* that should be copied instead of retained. --class TraceStringWithCopy { --public: -- explicit TraceStringWithCopy(const char* str) : m_str(str) { } -- operator const char* () const { return m_str; } --private: -- const char* m_str; --}; -- --// Define setTraceValue for each allowed type. It stores the type and --// value in the return arguments. This allows this API to avoid declaring any --// structures so that it is portable to third_party libraries. --#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \ -- union_member, \ -- value_type_id) \ -- static inline void setTraceValue(actual_type arg, \ -- unsigned char* type, \ -- unsigned long long* value) { \ -- TraceValueUnion typeValue; \ -- typeValue.union_member = arg; \ -- *type = value_type_id; \ -- *value = typeValue.m_uint; \ -- } --// Simpler form for int types that can be safely casted. --#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \ -- value_type_id) \ -- static inline void setTraceValue(actual_type arg, \ -- unsigned char* type, \ -- unsigned long long* value) { \ -- *type = value_type_id; \ -- *value = static_cast(arg); \ -- } -- --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT) --INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT) --INTERNAL_DECLARE_SET_TRACE_VALUE(bool, m_bool, TRACE_VALUE_TYPE_BOOL) --INTERNAL_DECLARE_SET_TRACE_VALUE(double, m_double, TRACE_VALUE_TYPE_DOUBLE) --INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, m_pointer, -- TRACE_VALUE_TYPE_POINTER) --INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, m_string, -- TRACE_VALUE_TYPE_STRING) --INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, m_string, -- TRACE_VALUE_TYPE_COPY_STRING) -- --#undef INTERNAL_DECLARE_SET_TRACE_VALUE --#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT -- --static inline void setTraceValue(const std::string& arg, -- unsigned char* type, -- unsigned long long* value) { -- TraceValueUnion typeValue; -- typeValue.m_string = arg.data(); -- *type = TRACE_VALUE_TYPE_COPY_STRING; -- *value = typeValue.m_uint; --} -- --// These addTraceEvent template functions are defined here instead of in the --// macro, because the arg values could be temporary string objects. In order to --// store pointers to the internal c_str and pass through to the tracing API, the --// arg values must live throughout these procedures. -- --static inline void addTraceEvent(char phase, -- const unsigned char* categoryEnabled, -- const char* name, -- unsigned long long id, -- unsigned char flags) { -- TRACE_EVENT_API_ADD_TRACE_EVENT( -- phase, categoryEnabled, name, id, -- zeroNumArgs, 0, 0, 0, -- flags); --} -- --template --static inline void addTraceEvent(char phase, -- const unsigned char* categoryEnabled, -- const char* name, -- unsigned long long id, -- unsigned char flags, -- const char* arg1Name, -- const ARG1_TYPE& arg1Val) { -- const int numArgs = 1; -- unsigned char argTypes[1]; -- unsigned long long argValues[1]; -- setTraceValue(arg1Val, &argTypes[0], &argValues[0]); -- TRACE_EVENT_API_ADD_TRACE_EVENT( -- phase, categoryEnabled, name, id, -- numArgs, &arg1Name, argTypes, argValues, -- flags); --} -- --template --static inline void addTraceEvent(char phase, -- const unsigned char* categoryEnabled, -- const char* name, -- unsigned long long id, -- unsigned char flags, -- const char* arg1Name, -- const ARG1_TYPE& arg1Val, -- const char* arg2Name, -- const ARG2_TYPE& arg2Val) { -- const int numArgs = 2; -- const char* argNames[2] = { arg1Name, arg2Name }; -- unsigned char argTypes[2]; -- unsigned long long argValues[2]; -- setTraceValue(arg1Val, &argTypes[0], &argValues[0]); -- setTraceValue(arg2Val, &argTypes[1], &argValues[1]); -- return TRACE_EVENT_API_ADD_TRACE_EVENT( -- phase, categoryEnabled, name, id, -- numArgs, argNames, argTypes, argValues, -- flags); --} -- --// Used by TRACE_EVENTx macro. Do not use directly. --class TraceEndOnScopeClose { --public: -- // Note: members of m_data intentionally left uninitialized. See initialize. -- TraceEndOnScopeClose() : m_pdata(0) { } -- ~TraceEndOnScopeClose() -- { -- if (m_pdata) -- addEventIfEnabled(); -- } -- -- void initialize(const unsigned char* categoryEnabled, -- const char* name) -- { -- m_data.categoryEnabled = categoryEnabled; -- m_data.name = name; -- m_pdata = &m_data; -- } -- --private: -- // Add the end event if the category is still enabled. -- void addEventIfEnabled() -- { -- // Only called when m_pdata is non-null. -- if (*m_pdata->categoryEnabled) { -- TRACE_EVENT_API_ADD_TRACE_EVENT( -- TRACE_EVENT_PHASE_END, -- m_pdata->categoryEnabled, -- m_pdata->name, noEventId, -- zeroNumArgs, 0, 0, 0, -- TRACE_EVENT_FLAG_NONE); -- } -- } -- -- // This Data struct workaround is to avoid initializing all the members -- // in Data during construction of this object, since this object is always -- // constructed, even when tracing is disabled. If the members of Data were -- // members of this class instead, compiler warnings occur about potential -- // uninitialized accesses. -- struct Data { -- const unsigned char* categoryEnabled; -- const char* name; -- }; -- Data* m_pdata; -- Data m_data; --}; -- --// TraceEventSamplingStateScope records the current sampling state --// and sets a new sampling state. When the scope exists, it restores --// the sampling state having recorded. --template --class SamplingStateScope { --public: -- SamplingStateScope(const char* categoryAndName) -- { -- m_previousState = SamplingStateScope::current(); -- SamplingStateScope::set(categoryAndName); -- } -- -- ~SamplingStateScope() -- { -- SamplingStateScope::set(m_previousState); -- } -- -- // FIXME: Make load/store to traceSamplingState[] thread-safe and atomic. -- static inline const char* current() -- { -- return reinterpret_cast(*gl::traceSamplingState[BucketNumber]); -- } -- static inline void set(const char* categoryAndName) -- { -- *gl::traceSamplingState[BucketNumber] = reinterpret_cast(const_cast(categoryAndName)); -- } -- --private: -- const char* m_previousState; --}; -- --} // namespace TraceEvent -- --} // namespace gl -- --#endif -diff --git a/src/angle/src/common/common.pri b/src/angle/src/common/common.pri -index fd1c31c..8baedc5 100644 ---- a/src/angle/src/common/common.pri -+++ b/src/angle/src/common/common.pri -@@ -51,7 +51,6 @@ static: DEFINES *= QT_OPENGL_ES_2_ANGLE_STATIC - HEADERS += \ - $$ANGLE_DIR/src/common/angleutils.h \ - $$ANGLE_DIR/src/common/debug.h \ -- $$ANGLE_DIR/src/common/event_tracer.h \ - $$ANGLE_DIR/src/common/mathutil.h \ - $$ANGLE_DIR/src/common/platform.h \ - $$ANGLE_DIR/src/common/RefCountObject.h \ -@@ -61,7 +60,6 @@ HEADERS += \ - SOURCES += \ - $$ANGLE_DIR/src/common/angleutils.cpp \ - $$ANGLE_DIR/src/common/debug.cpp \ -- $$ANGLE_DIR/src/common/event_tracer.cpp \ - $$ANGLE_DIR/src/common/RefCountObject.cpp \ - $$ANGLE_DIR/src/common/tls.cpp - -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0001-Fix-compilation-for-MSVC-2008-and-std-tuple.patch b/src/angle/patches/0001-Fix-compilation-for-MSVC-2008-and-std-tuple.patch deleted file mode 100644 index f2252540eb..0000000000 --- a/src/angle/patches/0001-Fix-compilation-for-MSVC-2008-and-std-tuple.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 3ea314039783d2e6e558cb10aa86dbf278631eef Mon Sep 17 00:00:00 2001 -From: Thomas Hartmann -Date: Tue, 16 Sep 2014 23:24:24 +0300 -Subject: [PATCH 01/16] Fix compilation for MSVC 2008 and std::tuple - -For MSVC 2008 make_tuple is in the tr1 namespace. - -Change-Id: I4a51f6cabdf068993869b404b12ed1484a21a9d4 ---- - src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp -index d472e14..f68ac38 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/IndexRangeCache.cpp -@@ -111,7 +111,11 @@ IndexRangeCache::IndexRange::IndexRange(GLenum typ, intptr_t off, GLsizei c) - - bool IndexRangeCache::IndexRange::operator<(const IndexRange& rhs) const - { -+#if defined(_MSC_VER) && _MSC_VER < 1600 -+ return std::tr1::make_tuple(type, offset, count) < std::tr1::make_tuple(rhs.type, rhs.offset, rhs.count); -+#else - return std::make_tuple(type, offset, count) < std::make_tuple(rhs.type, rhs.offset, rhs.count); -+#endif - } - - IndexRangeCache::IndexBounds::IndexBounds() --- -1.9.0.msysgit.0 - diff --git a/src/angle/patches/0002-Fix-compilation-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch b/src/angle/patches/0002-Fix-compilation-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch deleted file mode 100644 index 322d121149..0000000000 --- a/src/angle/patches/0002-Fix-compilation-of-ANGLE-with-mingw-tdm64-gcc-4.8.1.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 9f1217589c029d2f91e863c54f7f9d52ef496f71 Mon Sep 17 00:00:00 2001 -From: Kai Koehne -Date: Tue, 16 Sep 2014 23:33:42 +0300 -Subject: [PATCH 02/16] Fix compilation of ANGLE with mingw-tdm64 gcc 4.8.1 - -Do not rely on sprintf_s being declared/defined. This also fixes -deployment to Windows XP. - -See https://chromium-review.googlesource.com/#/c/182975/ for a similar -commit proposed upstream. - -Task-number: QTBUG-36242 -Change-Id: I520e2f61aeab34963e7a57baafd413c7db93f110 ---- - src/3rdparty/angle/src/libEGL/Display.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp -index ecf3395..aaebdb3 100644 ---- a/src/3rdparty/angle/src/libEGL/Display.cpp -+++ b/src/3rdparty/angle/src/libEGL/Display.cpp -@@ -597,7 +597,7 @@ void Display::initVendorString() - if (mRenderer && mRenderer->getLUID(&adapterLuid)) - { - char adapterLuidString[64]; -- sprintf_s(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); -+ snprintf(adapterLuidString, sizeof(adapterLuidString), " (adapter LUID: %08x%08x)", adapterLuid.HighPart, adapterLuid.LowPart); - - mVendorString += adapterLuidString; - } --- -1.9.0.msysgit.0 - diff --git a/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch b/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch index 1dfe6154e7..45a3f17cca 100644 --- a/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch +++ b/src/angle/patches/0004-Make-it-possible-to-link-ANGLE-statically-for-single.patch @@ -1,6 +1,6 @@ -From cb00356bad800ca2397301cb8b79ad0b097bddd8 Mon Sep 17 00:00:00 2001 +From 3a39939b5eba9f788789961c4800ba62618f758c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint -Date: Tue, 16 Sep 2014 23:43:00 +0300 +Date: Tue, 11 Nov 2014 10:26:32 +0200 Subject: [PATCH 04/16] Make it possible to link ANGLE statically for single-thread use. @@ -11,8 +11,8 @@ Change-Id: Ifab25a820adf5953bb3b09036de53dbf7f1a7fd5 --- src/3rdparty/angle/include/KHR/khrplatform.h | 2 +- src/3rdparty/angle/src/libEGL/main.cpp | 10 ++++++++++ - src/3rdparty/angle/src/libGLESv2/main.cpp | 10 ++++++++++ - 3 files changed, 21 insertions(+), 1 deletion(-) + src/3rdparty/angle/src/libGLESv2/main.cpp | 10 ++++++++-- + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/angle/include/KHR/khrplatform.h b/src/3rdparty/angle/include/KHR/khrplatform.h index c9e6f17..1ac2d3f 100644 @@ -28,7 +28,7 @@ index c9e6f17..1ac2d3f 100644 #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp -index 0f8439c..8a1baef 100644 +index d1489f2..e88cad7 100644 --- a/src/3rdparty/angle/src/libEGL/main.cpp +++ b/src/3rdparty/angle/src/libEGL/main.cpp @@ -49,6 +49,8 @@ void DeallocateCurrent() @@ -40,7 +40,7 @@ index 0f8439c..8a1baef 100644 extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) -@@ -100,16 +102,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved +@@ -108,16 +110,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved return TRUE; } @@ -64,26 +64,27 @@ index 0f8439c..8a1baef 100644 +#endif } - void setCurrentError(EGLint error) + void recordError(const Error &error) diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp -index 4444d1a..1c577bc 100644 +index 3ac00d5..00f63ae 100644 --- a/src/3rdparty/angle/src/libGLESv2/main.cpp +++ b/src/3rdparty/angle/src/libGLESv2/main.cpp -@@ -46,6 +46,8 @@ void DeallocateCurrent() +@@ -74,7 +74,7 @@ void DeallocateCurrent() } -+#ifndef QT_OPENGL_ES_2_ANGLE_STATIC -+ +-#ifdef ANGLE_PLATFORM_WINDOWS ++#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(QT_OPENGL_ES_2_ANGLE_STATIC) extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { switch (reason) -@@ -82,16 +84,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved +@@ -117,18 +117,24 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved + return TRUE; } +-#endif ++#endif // ANGLE_PLATFORM_WINDOWS && !QT_OPENGL_ES_2_ANGLE_STATIC -+#endif // !QT_OPENGL_ES_2_ANGLE_STATIC -+ namespace gl { @@ -104,5 +105,5 @@ index 4444d1a..1c577bc 100644 void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0005-Fix-build-when-SSE2-is-not-available.patch b/src/angle/patches/0005-Fix-build-when-SSE2-is-not-available.patch deleted file mode 100644 index 78c3e0fbe8..0000000000 --- a/src/angle/patches/0005-Fix-build-when-SSE2-is-not-available.patch +++ /dev/null @@ -1,84 +0,0 @@ -From df225c023963f37737b7e2d020c8f89a5d5f878e Mon Sep 17 00:00:00 2001 -From: Andy Shaw -Date: Tue, 16 Sep 2014 23:49:50 +0300 -Subject: [PATCH 05/16] Fix build when SSE2 is not available. - -Although SSE2 support is detected at runtime it still may not be -available at build time, so we have to ensure it only uses SSE2 -when it is available at build time too. - -Change-Id: I86c45a6466ab4cec79aa0f62b0d5230a78ad825a ---- - src/3rdparty/angle/src/common/mathutil.h | 2 ++ - src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp | 8 ++++++++ - 2 files changed, 10 insertions(+) - -diff --git a/src/3rdparty/angle/src/common/mathutil.h b/src/3rdparty/angle/src/common/mathutil.h -index ffcb908..52f2bc1 100644 ---- a/src/3rdparty/angle/src/common/mathutil.h -+++ b/src/3rdparty/angle/src/common/mathutil.h -@@ -118,6 +118,7 @@ inline bool supportsSSE2() - return supports; - } - -+#if defined(_M_IX86) || defined(_M_AMD64) // ARM doesn't provide __cpuid() - int info[4]; - __cpuid(info, 0); - -@@ -127,6 +128,7 @@ inline bool supportsSSE2() - - supports = (info[3] >> 26) & 1; - } -+#endif - - checked = true; - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp -index cc20d94..f777b30 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/loadimageSSE2.cpp -@@ -10,6 +10,10 @@ - - #include "libGLESv2/renderer/loadimage.h" - -+#if !defined(__SSE2__) && (defined(_M_X64) || _M_IX86_FP == 2) -+#define __SSE2__ -+#endif -+ - namespace rx - { - -@@ -17,6 +21,7 @@ void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) - { -+#ifdef __SSE2__ - __m128i zeroWide = _mm_setzero_si128(); - - for (size_t z = 0; z < depth; z++) -@@ -54,12 +59,14 @@ void LoadA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - } - } - } -+#endif - } - - void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - const uint8_t *input, size_t inputRowPitch, size_t inputDepthPitch, - uint8_t *output, size_t outputRowPitch, size_t outputDepthPitch) - { -+#ifdef __SSE2__ - __m128i brMask = _mm_set1_epi32(0x00ff00ff); - - for (size_t z = 0; z < depth; z++) -@@ -99,6 +106,7 @@ void LoadRGBA8ToBGRA8_SSE2(size_t width, size_t height, size_t depth, - } - } - } -+#endif - } - - } --- -1.9.0.msysgit.0 - diff --git a/src/angle/patches/0006-Fix-compilation-of-libGLESv2-with-older-MinGW-w64-he.patch b/src/angle/patches/0006-Fix-compilation-of-libGLESv2-with-older-MinGW-w64-he.patch deleted file mode 100644 index e60bebd233..0000000000 --- a/src/angle/patches/0006-Fix-compilation-of-libGLESv2-with-older-MinGW-w64-he.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 2a8568e6f44731df96f6567ffcc59a65ad2b3f29 Mon Sep 17 00:00:00 2001 -From: Kai Koehne -Date: Tue, 16 Sep 2014 23:55:25 +0300 -Subject: [PATCH 06/16] Fix compilation of libGLESv2 with older MinGW-w64 - headers - -Fix compilation of libGLESv2 for mingw-headers predating MinGW-w64 -svn commit 5567 (like MinGW-builds gcc 4.7.2-rev8, the toolchain -we officially support). - -Commit 5567 added the D3DCOMPILER_DLL define to d3dcompiler.h, but with -a trailing semicolon that has then fixed in commit 5783. Any toolchain -that ships MinGW-w64 headers from a version in between (like -MinGW-builds gcc 4.7.2-rev11) will unfortunately remain broken. - -Change-Id: I31272a1a991c4fc0f1611f8fb7510be51d6bb925 ---- - .../angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index acbd852..eb0dfa5 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -10,6 +10,21 @@ - - #include "common/utilities.h" - -+#if defined(__MINGW32__) && !defined(D3DCOMPILER_DLL) -+ -+// Add define + typedefs for older MinGW-w64 headers (pre 5783) -+ -+#define D3DCOMPILER_DLL L"d3dcompiler_43.dll" -+ -+HRESULT WINAPI D3DCompile(const void *data, SIZE_T data_size, const char *filename, -+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, -+ const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); -+typedef HRESULT (WINAPI *pD3DCompile)(const void *data, SIZE_T data_size, const char *filename, -+ const D3D_SHADER_MACRO *defines, ID3DInclude *include, const char *entrypoint, -+ const char *target, UINT sflags, UINT eflags, ID3DBlob **shader, ID3DBlob **error_messages); -+ -+#endif // __MINGW32__ && !D3DCOMPILER_DLL -+ - namespace rx - { - --- -1.9.0.msysgit.0 - diff --git a/src/angle/patches/0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch b/src/angle/patches/0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch deleted file mode 100644 index c796ebc95e..0000000000 --- a/src/angle/patches/0007-Fix-ANGLE-build-with-Microsoft-Visual-Studio-14-CTP.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 76152feea8265f40fec8c6e53f976dbd82fb6c80 Mon Sep 17 00:00:00 2001 -From: Thiago Macieira -Date: Tue, 16 Sep 2014 23:56:43 +0300 -Subject: [PATCH 07/16] Fix ANGLE build with Microsoft Visual Studio "14" CTP - -This version has a few new C99 support added, including snprintf. - -Change-Id: I5776456fd94254a64f08791f59bc775cb24c9b7f ---- - src/3rdparty/angle/src/common/angleutils.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/3rdparty/angle/src/common/angleutils.h b/src/3rdparty/angle/src/common/angleutils.h -index 50a4132..ddbbd5f 100644 ---- a/src/3rdparty/angle/src/common/angleutils.h -+++ b/src/3rdparty/angle/src/common/angleutils.h -@@ -135,7 +135,7 @@ inline std::string Str(int i) - std::string FormatString(const char *fmt, va_list vararg); - std::string FormatString(const char *fmt, ...); - --#if defined(_MSC_VER) -+#if defined(_MSC_VER) && _MSC_VER < 1900 - #define snprintf _snprintf - #endif - --- -1.9.0.msysgit.0 - diff --git a/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch b/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch index 7c821580d0..801db67682 100644 --- a/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch +++ b/src/angle/patches/0008-ANGLE-Dynamically-load-D3D-compiler-from-a-list-or-t.patch @@ -1,6 +1,6 @@ -From 4f6dd1f7cdce3340723cc23e0aea27b156fa3497 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Tue, 16 Sep 2014 23:59:40 +0300 +From 4a5960465d1632ab089320fcbba4af294d58fd9a Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Fri, 7 Nov 2014 14:05:36 +0200 Subject: [PATCH 08/16] ANGLE: Dynamically load D3D compiler from a list or the environment @@ -11,29 +11,28 @@ QT_D3DCOMPILER_DLL. Change-Id: I0d7a8a8a36cc571836f8fa59ea14513b9b19c19b --- - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 27 +++++++++++++++++++--- - 1 file changed, 24 insertions(+), 3 deletions(-) + .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 27 ++++++++++++++++++++++ + 1 file changed, 27 insertions(+) diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index eb0dfa5..5715d5f 100644 +index bfeaf51..9d003b4 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -25,6 +25,10 @@ typedef HRESULT (WINAPI *pD3DCompile)(const void *data, SIZE_T data_size, const - - #endif // __MINGW32__ && !D3DCOMPILER_DLL +@@ -11,6 +11,10 @@ + #include "common/features.h" + #include "common/utilities.h" +#ifndef QT_D3DCOMPILER_DLL +#define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL +#endif + - namespace rx + // Definitions local to the translation unit + namespace { - -@@ -59,10 +63,27 @@ bool HLSLCompiler::initialize() +@@ -132,6 +136,29 @@ bool HLSLCompiler::initialize() } #endif // ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES -- if (!mD3DCompilerModule) + // Load the compiler DLL specified by the environment, or default to QT_D3DCOMPILER_DLL + const wchar_t *defaultCompiler = _wgetenv(L"QT_D3DCOMPILER_DLL"); + if (!defaultCompiler) @@ -51,15 +50,15 @@ index eb0dfa5..5715d5f 100644 + + // Load the first available known compiler DLL + for (int i = 0; compilerDlls[i]; ++i) - { -- // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. -- mD3DCompilerModule = LoadLibrary(D3DCOMPILER_DLL); ++ { + mD3DCompilerModule = LoadLibrary(compilerDlls[i]); + if (mD3DCompilerModule) + break; - } - ++ } ++ if (!mD3DCompilerModule) + { + // Load the version of the D3DCompiler DLL associated with the Direct3D version ANGLE was built with. -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0009-ANGLE-Support-WinRT.patch b/src/angle/patches/0009-ANGLE-Support-WinRT.patch index f4bae46b63..a38fb4ea13 100644 --- a/src/angle/patches/0009-ANGLE-Support-WinRT.patch +++ b/src/angle/patches/0009-ANGLE-Support-WinRT.patch @@ -1,1126 +1,673 @@ -From 7ff7dd46f54e23ae309887366bf477de9c33005b Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Wed, 17 Sep 2014 00:58:29 +0300 +From 4d150ba3814f824f1cadaedbdb83d0ac79d0e1a2 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Fri, 14 Nov 2014 09:28:11 +0200 Subject: [PATCH 09/16] ANGLE: Support WinRT -This enables EGL for WinRT's native types, and adjusts some codepaths -to accommodate differences between desktop Windows and WinRT. +Tweak ANGLE's existing support for WinRT to allow for changing the +window size on Windows Phone. -- WinRT native handles added to eglplatform.h -- References to native handles in libEGL/libGLESv2 follow eglplatform.h -- D3D 11.1 structures and methods used when necessary -- TLS replaced with thread attribute -- LocalAlloc/Free replaced with Heap API - -Change-Id: Ia90377e700d335a1c569c2145008dd4b0dfd84d3 -Reviewed-by: Friedemann Kleint +Change-Id: Ia312b5318b977838a2953f1f530487cbf24974bc --- - src/3rdparty/angle/include/EGL/eglplatform.h | 10 +- - src/3rdparty/angle/src/common/platform.h | 3 + - src/3rdparty/angle/src/common/tls.cpp | 37 ++++- - src/3rdparty/angle/src/common/tls.h | 6 +- - src/3rdparty/angle/src/common/utilities.cpp | 51 +++++- - src/3rdparty/angle/src/libEGL/Display.cpp | 13 +- - src/3rdparty/angle/src/libEGL/Display.h | 6 +- - src/3rdparty/angle/src/libEGL/Surface.cpp | 185 ++++++++++++++++++++- - src/3rdparty/angle/src/libEGL/Surface.h | 37 ++++- - src/3rdparty/angle/src/libEGL/libEGL.cpp | 8 +- - src/3rdparty/angle/src/libEGL/main.cpp | 21 +++ - src/3rdparty/angle/src/libGLESv2/main.cpp | 20 +++ - src/3rdparty/angle/src/libGLESv2/main.h | 4 + - .../angle/src/libGLESv2/renderer/Renderer.h | 2 +- - .../angle/src/libGLESv2/renderer/SwapChain.h | 15 +- - .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 11 +- - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 13 +- - .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 4 +- - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 73 ++++++-- - .../src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h | 6 +- - .../src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp | 2 +- - .../src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h | 2 +- - 22 files changed, 481 insertions(+), 48 deletions(-) + src/3rdparty/angle/include/EGL/eglplatform.h | 5 +- + src/3rdparty/angle/src/common/NativeWindow.h | 7 +- + src/3rdparty/angle/src/common/platform.h | 4 +- + .../angle/src/common/win32/NativeWindow.cpp | 2 +- + .../src/common/winrt/CoreWindowNativeWindow.cpp | 87 +++++++++++++--------- + .../src/common/winrt/CoreWindowNativeWindow.h | 48 ++---------- + .../src/common/winrt/InspectableNativeWindow.cpp | 8 +- + .../src/common/winrt/InspectableNativeWindow.h | 7 +- + .../common/winrt/SwapChainPanelNativeWindow.cpp | 2 +- + .../src/common/winrt/SwapChainPanelNativeWindow.h | 2 +- + src/3rdparty/angle/src/libEGL/Display.h | 1 + + src/3rdparty/angle/src/libEGL/Surface.cpp | 45 ++++++++--- + src/3rdparty/angle/src/libEGL/Surface.h | 4 + + src/3rdparty/angle/src/libEGL/libEGL.cpp | 20 +++++ + .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 2 +- + .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 74 +++++++++++------- + .../src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h | 2 + + 17 files changed, 189 insertions(+), 131 deletions(-) diff --git a/src/3rdparty/angle/include/EGL/eglplatform.h b/src/3rdparty/angle/include/EGL/eglplatform.h -index 3ab8844..ea9f577 100644 +index 3793e57..2eb3674 100644 --- a/src/3rdparty/angle/include/EGL/eglplatform.h +++ b/src/3rdparty/angle/include/EGL/eglplatform.h -@@ -67,7 +67,15 @@ - * implementations. - */ - --#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ -+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) /* Windows Runtime */ -+ -+struct IUnknown; -+ -+typedef IUnknown *EGLNativeDisplayType; -+typedef void *EGLNativePixmapType; -+typedef IUnknown *EGLNativeWindowType; -+ -+#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN 1 +@@ -73,13 +73,14 @@ #endif -diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index d07297d..387ba41 100644 ---- a/src/3rdparty/angle/src/common/platform.h -+++ b/src/3rdparty/angle/src/common/platform.h -@@ -11,6 +11,9 @@ + #include - #if defined(_WIN32) || defined(_WIN64) - # define ANGLE_PLATFORM_WINDOWS 1 -+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -+# define ANGLE_PLATFORM_WINRT 1 -+# endif - #elif defined(__APPLE__) - # define ANGLE_PLATFORM_APPLE 1 - # define ANGLE_PLATFORM_POSIX 1 -diff --git a/src/3rdparty/angle/src/common/tls.cpp b/src/3rdparty/angle/src/common/tls.cpp -index 6b78219..c46fab5 100644 ---- a/src/3rdparty/angle/src/common/tls.cpp -+++ b/src/3rdparty/angle/src/common/tls.cpp -@@ -10,11 +10,28 @@ +-typedef HDC EGLNativeDisplayType; + typedef HBITMAP EGLNativePixmapType; - #include - -+#if defined(ANGLE_PLATFORM_WINRT) -+#include -+std::vector *tls = nullptr; -+std::vector *freeIndices = nullptr; -+#endif -+ - TLSIndex CreateTLSIndex() - { - TLSIndex index; - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (!tls) -+ tls = new std::vector; -+ if (freeIndices && !freeIndices->empty()) { -+ index = freeIndices->back(); -+ freeIndices->pop_back(); -+ return index; -+ } else { -+ tls->push_back(nullptr); -+ return tls->size() - 1; -+ } -+#elif defined(ANGLE_PLATFORM_WINDOWS) - index = TlsAlloc(); - #elif defined(ANGLE_PLATFORM_POSIX) - // Create global pool key -@@ -36,7 +53,12 @@ bool DestroyTLSIndex(TLSIndex index) - return false; - } - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (!freeIndices) -+ freeIndices = new std::vector; -+ freeIndices->push_back(index); -+ return true; -+#elif ANGLE_PLATFORM_WINDOWS - return (TlsFree(index) == TRUE); - #elif defined(ANGLE_PLATFORM_POSIX) - return (pthread_key_delete(index) == 0); -@@ -51,7 +73,10 @@ bool SetTLSValue(TLSIndex index, void *value) - return false; - } - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ tls->at(index) = value; -+ return true; -+#elif defined(ANGLE_PLATFORM_WINDOWS) - return (TlsSetValue(index, value) == TRUE); - #elif defined(ANGLE_PLATFORM_POSIX) - return (pthread_setspecific(index, value) == 0); -@@ -60,13 +85,17 @@ bool SetTLSValue(TLSIndex index, void *value) - - void *GetTLSValue(TLSIndex index) - { -+#if !defined(ANGLE_PLATFORM_WINRT) // Valid on WinRT, as Alloc handles the index creation - assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); -+#endif - if (index == TLS_INVALID_INDEX) - { - return NULL; - } - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ return tls->at(index); -+#elif defined(ANGLE_PLATFORM_WINDOWS) - return TlsGetValue(index); - #elif defined(ANGLE_PLATFORM_POSIX) - return pthread_getspecific(index); -diff --git a/src/3rdparty/angle/src/common/tls.h b/src/3rdparty/angle/src/common/tls.h -index 4b25fbc..c40ae1a 100644 ---- a/src/3rdparty/angle/src/common/tls.h -+++ b/src/3rdparty/angle/src/common/tls.h -@@ -11,7 +11,11 @@ - - #include "common/platform.h" - --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ typedef size_t TLSIndex; -+# define TLS_OUT_OF_INDEXES (static_cast(-1)) -+# define TLS_INVALID_INDEX TLS_OUT_OF_INDEXES -+#elif defined(ANGLE_PLATFORM_WINDOWS) - typedef DWORD TLSIndex; - # define TLS_INVALID_INDEX (TLS_OUT_OF_INDEXES) - #elif defined(ANGLE_PLATFORM_POSIX) -diff --git a/src/3rdparty/angle/src/common/utilities.cpp b/src/3rdparty/angle/src/common/utilities.cpp -index 405f119..4b8e325 100644 ---- a/src/3rdparty/angle/src/common/utilities.cpp -+++ b/src/3rdparty/angle/src/common/utilities.cpp -@@ -9,6 +9,14 @@ - #include "common/utilities.h" - #include "common/mathutil.h" - #include "common/platform.h" -+#if defined(ANGLE_PLATFORM_WINRT) -+# include -+# include -+# include -+# include -+ using namespace Microsoft::WRL; -+ using namespace ABI::Windows::Storage; -+#endif - - #include - -@@ -441,7 +449,48 @@ int VariableSortOrder(GLenum type) - - std::string getTempPath() - { --#ifdef ANGLE_PLATFORM_WINDOWS -+#if defined(ANGLE_PLATFORM_WINRT) -+ static std::string path; -+ -+ while (path.empty()) -+ { -+ ComPtr factory; -+ Wrappers::HStringReference classId(RuntimeClass_Windows_Storage_ApplicationData); -+ HRESULT result = RoGetActivationFactory(classId.Get(), IID_PPV_ARGS(&factory)); -+ if (FAILED(result)) -+ break; -+ -+ ComPtr applicationData; -+ result = factory->get_Current(&applicationData); -+ if (FAILED(result)) -+ break; -+ -+ ComPtr storageFolder; -+ result = applicationData->get_LocalFolder(&storageFolder); -+ if (FAILED(result)) -+ break; -+ -+ ComPtr localFolder; -+ result = storageFolder.As(&localFolder); -+ if (FAILED(result)) -+ break; -+ -+ HSTRING localFolderPath; -+ result = localFolder->get_Path(&localFolderPath); -+ if (FAILED(result)) -+ break; -+ -+ std::wstring_convert< std::codecvt_utf8 > converter; -+ path = converter.to_bytes(WindowsGetStringRawBuffer(localFolderPath, NULL)); -+ if (path.empty()) -+ { -+ UNREACHABLE(); -+ break; -+ } -+ } -+ -+ return path; -+#elif defined(ANGLE_PLATFORM_WINDOWS) - char path[MAX_PATH]; - DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); - if (pathLen == 0) -diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp -index aaebdb3..ba09631 100644 ---- a/src/3rdparty/angle/src/libEGL/Display.cpp -+++ b/src/3rdparty/angle/src/libEGL/Display.cpp -@@ -56,6 +56,10 @@ Display::Display(EGLNativeDisplayType displayId, EGLint displayType) - mRequestedDisplayType(displayType), - mRenderer(NULL) - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (mDisplayId) -+ mDisplayId->AddRef(); -+#endif - } - - Display::~Display() -@@ -68,6 +72,11 @@ Display::~Display() - { - displays->erase(iter); - } -+ -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (mDisplayId) -+ mDisplayId->Release(); -+#endif - } - - bool Display::initialize() -@@ -192,7 +201,7 @@ bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) - - - --EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList) -+EGLSurface Display::createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList) - { - const Config *configuration = mConfigSet.get(config); - EGLint postSubBufferSupported = EGL_FALSE; -@@ -493,7 +502,7 @@ bool Display::isValidSurface(egl::Surface *surface) - return mSurfaceSet.find(surface) != mSurfaceSet.end(); - } - --bool Display::hasExistingWindowSurface(HWND window) -+bool Display::hasExistingWindowSurface(EGLNativeWindowType window) - { - for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) - { -diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h -index 250878f..73ba767 100644 ---- a/src/3rdparty/angle/src/libEGL/Display.h -+++ b/src/3rdparty/angle/src/libEGL/Display.h -@@ -43,7 +43,7 @@ class Display - bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); - bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); - -- EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList); -+ EGLSurface createWindowSurface(EGLNativeWindowType window, EGLConfig config, const EGLint *attribList); - EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList); - EGLContext createContext(EGLConfig configHandle, EGLint clientVersion, const gl::Context *shareContext, bool notifyResets, bool robustAccess); - -@@ -54,7 +54,7 @@ class Display - bool isValidConfig(EGLConfig config); - bool isValidContext(gl::Context *context); - bool isValidSurface(egl::Surface *surface); -- bool hasExistingWindowSurface(HWND window); -+ bool hasExistingWindowSurface(EGLNativeWindowType window); - - rx::Renderer *getRenderer() { return mRenderer; }; - -@@ -65,6 +65,8 @@ class Display - const char *getExtensionString() const; - const char *getVendorString() const; - -+ EGLNativeDisplayType getDisplayId() const { return mDisplayId; } -+ - private: - DISALLOW_COPY_AND_ASSIGN(Display); - -diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp -index 13b0f20..fa79961 100644 ---- a/src/3rdparty/angle/src/libEGL/Surface.cpp -+++ b/src/3rdparty/angle/src/libEGL/Surface.cpp -@@ -22,10 +22,20 @@ - #include "libEGL/main.h" - #include "libEGL/Display.h" - -+#if defined(ANGLE_PLATFORM_WINRT) -+# include "wrl.h" -+# include "windows.graphics.display.h" -+# include "windows.ui.core.h" -+using namespace ABI::Windows::Graphics::Display; -+using namespace ABI::Windows::Foundation; -+using namespace ABI::Windows::UI::Core; -+using namespace Microsoft::WRL; -+#endif -+ - namespace egl - { - --Surface::Surface(Display *display, const Config *config, HWND window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) -+Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) - : mDisplay(display), mConfig(config), mWindow(window), mPostSubBufferSupported(postSubBufferSupported) - { - mRenderer = mDisplay->getRenderer(); -@@ -43,6 +53,17 @@ Surface::Surface(Display *display, const Config *config, HWND window, EGLint fix - mHeight = height; - setSwapInterval(1); - mFixedSize = fixedSize; -+ mSwapFlags = rx::SWAP_NORMAL; -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (mWindow) -+ mWindow->AddRef(); -+ mScaleFactor = 1.0; -+ mSizeToken.value = 0; -+ mDpiToken.value = 0; -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ mOrientationToken.value = 0; -+# endif -+#endif - - subclassWindow(); - } -@@ -64,16 +85,86 @@ Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGL - setSwapInterval(1); - // This constructor is for offscreen surfaces, which are always fixed-size. - mFixedSize = EGL_TRUE; -+ mSwapFlags = rx::SWAP_NORMAL; -+#if defined(ANGLE_PLATFORM_WINRT) -+ mScaleFactor = 1.0; -+ mSizeToken.value = 0; -+ mDpiToken.value = 0; -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ mOrientationToken.value = 0; -+# endif -+#endif - } - - Surface::~Surface() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (mSizeToken.value) { -+ ComPtr coreWindow; -+ HRESULT hr = mWindow->QueryInterface(coreWindow.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ -+ hr = coreWindow->remove_SizeChanged(mSizeToken); -+ ASSERT(SUCCEEDED(hr)); -+ } -+ if (mDpiToken.value) { -+ ComPtr displayInformation; -+ HRESULT hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ -+ hr = displayInformation->remove_DpiChanged(mDpiToken); -+ ASSERT(SUCCEEDED(hr)); -+ } -+# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -+ if (mOrientationToken.value) { -+ ComPtr displayInformation; -+ HRESULT hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ -+ hr = displayInformation->remove_OrientationChanged(mOrientationToken); -+ ASSERT(SUCCEEDED(hr)); -+ } -+# endif -+#endif - unsubclassWindow(); - release(); - } - - bool Surface::initialize() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (!mFixedSize) { -+ HRESULT hr; -+ ComPtr displayInformation; -+ hr = mDisplay->getDisplayId()->QueryInterface(displayInformation.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ onDpiChanged(displayInformation.Get(), 0); -+ hr = displayInformation->add_DpiChanged(Callback>(this, &Surface::onDpiChanged).Get(), -+ &mDpiToken); -+ ASSERT(SUCCEEDED(hr)); -+ -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ onOrientationChanged(displayInformation.Get(), 0); -+ hr = displayInformation->add_OrientationChanged(Callback>(this, &Surface::onOrientationChanged).Get(), -+ &mOrientationToken); -+ ASSERT(SUCCEEDED(hr)); -+# endif -+ -+ ComPtr coreWindow; -+ hr = mWindow->QueryInterface(coreWindow.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ -+ Rect rect; -+ hr = coreWindow->get_Bounds(&rect); -+ ASSERT(SUCCEEDED(hr)); -+ mWidth = rect.Width * mScaleFactor; -+ mHeight = rect.Height * mScaleFactor; -+ hr = coreWindow->add_SizeChanged(Callback>(this, &Surface::onSizeChanged).Get(), -+ &mSizeToken); -+ ASSERT(SUCCEEDED(hr)); -+ } -+#endif -+ - if (!resetSwapChain()) - return false; - -@@ -90,6 +181,11 @@ void Surface::release() - mTexture->releaseTexImage(); - mTexture = NULL; - } -+ -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (mWindow) -+ mWindow->Release(); -+#endif - } - - bool Surface::resetSwapChain() -@@ -99,6 +195,7 @@ bool Surface::resetSwapChain() - int width; - int height; - -+#if !defined(ANGLE_PLATFORM_WINRT) - if (!mFixedSize) - { - RECT windowRect; -@@ -114,6 +211,7 @@ bool Surface::resetSwapChain() - height = windowRect.bottom - windowRect.top; - } - else -+#endif - { - // non-window surface - size is determined at creation - width = mWidth; -@@ -207,7 +305,7 @@ bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - return true; - } - -- EGLint status = mSwapChain->swapRect(x, y, width, height); -+ EGLint status = mSwapChain->swapRect(x, y, width, height, mSwapFlags); - - if (status == EGL_CONTEXT_LOST) - { -@@ -224,7 +322,7 @@ bool Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) - return true; - } - --HWND Surface::getWindowHandle() -+EGLNativeWindowType Surface::getWindowHandle() - { - return mWindow; - } -@@ -233,6 +331,7 @@ HWND Surface::getWindowHandle() - #define kSurfaceProperty _TEXT("Egl::SurfaceOwner") - #define kParentWndProc _TEXT("Egl::SurfaceParentWndProc") - -+#if !defined(ANGLE_PLATFORM_WINRT) - static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) - { - if (message == WM_SIZE) -@@ -246,9 +345,11 @@ static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam - WNDPROC prevWndFunc = reinterpret_cast(GetProp(hwnd, kParentWndProc)); - return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam); - } -+#endif - - void Surface::subclassWindow() - { -+#if !defined(ANGLE_PLATFORM_WINRT) - if (!mWindow) - { - return; -@@ -272,10 +373,14 @@ void Surface::subclassWindow() - SetProp(mWindow, kSurfaceProperty, reinterpret_cast(this)); - SetProp(mWindow, kParentWndProc, reinterpret_cast(oldWndProc)); - mWindowSubclassed = true; -+#else -+ mWindowSubclassed = false; -+#endif - } - - void Surface::unsubclassWindow() - { -+#if !defined(ANGLE_PLATFORM_WINRT) - if(!mWindowSubclassed) - { - return; -@@ -299,16 +404,18 @@ void Surface::unsubclassWindow() - RemoveProp(mWindow, kSurfaceProperty); - RemoveProp(mWindow, kParentWndProc); - mWindowSubclassed = false; -+#endif - } - - bool Surface::checkForOutOfDateSwapChain() - { -- RECT client; - int clientWidth = getWidth(); - int clientHeight = getHeight(); - bool sizeDirty = false; -+#if !defined(ANGLE_PLATFORM_WINRT) - if (!mFixedSize && !IsIconic(getWindowHandle())) - { -+ RECT client; - // The window is automatically resized to 150x22 when it's minimized, but the swapchain shouldn't be resized - // because that's not a useful size to render to. - if (!GetClientRect(getWindowHandle(), &client)) -@@ -322,6 +429,7 @@ bool Surface::checkForOutOfDateSwapChain() - clientHeight = client.bottom - client.top; - sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); - } -+#endif - - bool wasDirty = (mSwapIntervalDirty || sizeDirty); - -@@ -446,4 +554,73 @@ EGLenum Surface::getFormat() const - { - return mConfig->mRenderTargetFormat; - } -+ -+#if defined(ANGLE_PLATFORM_WINRT) -+ -+HRESULT Surface::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) -+{ -+ HRESULT hr; -+ Size size; -+ hr = args->get_Size(&size); -+ ASSERT(SUCCEEDED(hr)); -+ -+ resizeSwapChain(std::floor(size.Width * mScaleFactor + 0.5), -+ std::floor(size.Height * mScaleFactor + 0.5)); -+ -+ if (static_cast(getCurrentDrawSurface()) == this) -+ { -+ glMakeCurrent(glGetCurrentContext(), static_cast(getCurrentDisplay()), this); -+ } -+ -+ return S_OK; -+} -+ -+HRESULT Surface::onDpiChanged(IDisplayInformation *displayInformation, IInspectable *) -+{ -+ HRESULT hr; -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ ComPtr displayInformation2; -+ hr = displayInformation->QueryInterface(displayInformation2.GetAddressOf()); -+ ASSERT(SUCCEEDED(hr)); -+ -+ hr = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); -+ ASSERT(SUCCEEDED(hr)); -+# else -+ ResolutionScale resolutionScale; -+ hr = displayInformation->get_ResolutionScale(&resolutionScale); -+ ASSERT(SUCCEEDED(hr)); -+ -+ mScaleFactor = double(resolutionScale) / 100.0; -+# endif -+ return S_OK; -+} -+ -+# if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP -+HRESULT Surface::onOrientationChanged(IDisplayInformation *displayInformation, IInspectable *) -+{ -+ HRESULT hr; -+ DisplayOrientations orientation; -+ hr = displayInformation->get_CurrentOrientation(&orientation); -+ ASSERT(SUCCEEDED(hr)); -+ switch (orientation) { -+ default: -+ case DisplayOrientations_Portrait: -+ mSwapFlags = rx::SWAP_NORMAL; -+ break; -+ case DisplayOrientations_Landscape: -+ mSwapFlags = rx::SWAP_ROTATE_90; -+ break; -+ case DisplayOrientations_LandscapeFlipped: -+ mSwapFlags = rx::SWAP_ROTATE_270; -+ break; -+ case DisplayOrientations_PortraitFlipped: -+ mSwapFlags = rx::SWAP_ROTATE_180; -+ break; -+ } -+ return S_OK; -+} -+# endif -+ -+#endif -+ - } -diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h -index 24c66b7..ebffce8fe 100644 ---- a/src/3rdparty/angle/src/libEGL/Surface.h -+++ b/src/3rdparty/angle/src/libEGL/Surface.h -@@ -15,6 +15,20 @@ - - #include "common/angleutils.h" - -+#if defined(ANGLE_PLATFORM_WINRT) -+#include -+namespace ABI { namespace Windows { -+ namespace UI { namespace Core { -+ struct ICoreWindow; -+ struct IWindowSizeChangedEventArgs; -+ } } -+ namespace Graphics { namespace Display { -+ struct IDisplayInformation; -+ } } -+} } -+struct IInspectable; -+#endif -+ - namespace gl - { - class Texture2D; -@@ -33,7 +47,7 @@ class Config; - class Surface - { - public: -- Surface(Display *display, const egl::Config *config, HWND window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported); -+ Surface(Display *display, const egl::Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported); - Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget); - - virtual ~Surface(); -@@ -42,7 +56,7 @@ class Surface - void release(); - bool resetSwapChain(); - -- HWND getWindowHandle(); -+ EGLNativeWindowType getWindowHandle(); - bool swap(); - bool postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height); - -@@ -71,6 +85,14 @@ class Surface - private: - DISALLOW_COPY_AND_ASSIGN(Surface); - -+#if defined(ANGLE_PLATFORM_WINRT) -+ HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); -+ HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -+# endif -+#endif -+ - Display *const mDisplay; - rx::Renderer *mRenderer; - -@@ -83,7 +105,7 @@ private: - bool resetSwapChain(int backbufferWidth, int backbufferHeight); - bool swapRect(EGLint x, EGLint y, EGLint width, EGLint height); - -- const HWND mWindow; // Window that the surface is created for. -+ const EGLNativeWindowType mWindow; // Window that the surface is created for. - bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking - const egl::Config *mConfig; // EGL config surface was created with - EGLint mHeight; // Height of surface -@@ -104,9 +126,18 @@ private: - EGLint mSwapInterval; - EGLint mPostSubBufferSupported; - EGLint mFixedSize; -+ EGLint mSwapFlags; - - bool mSwapIntervalDirty; - gl::Texture2D *mTexture; -+#if defined(ANGLE_PLATFORM_WINRT) -+ double mScaleFactor; -+ EventRegistrationToken mSizeToken; -+ EventRegistrationToken mDpiToken; -+# if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ EventRegistrationToken mOrientationToken; -+# endif -+#endif - }; - } - -diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index 7ce2b93..7ea11c5 100644 ---- a/src/3rdparty/angle/src/libEGL/libEGL.cpp -+++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp -@@ -13,6 +13,7 @@ - - #include "common/debug.h" - #include "common/version.h" -+#include "common/platform.h" - #include "libGLESv2/Context.h" - #include "libGLESv2/Texture.h" - #include "libGLESv2/main.h" -@@ -120,12 +121,13 @@ EGLDisplay __stdcall eglGetPlatformDisplayEXT(EGLenum platform, void *native_dis - } - - EGLNativeDisplayType displayId = static_cast(native_display); -- -+#if !defined(ANGLE_PLATFORM_WINRT) - // Validate the display device context - if (WindowFromDC(displayId) == NULL) - { - return egl::success(EGL_NO_DISPLAY); - } -+#endif - - EGLint requestedDisplayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; - if (attrib_list) -@@ -327,14 +329,16 @@ EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EG - return EGL_NO_SURFACE; - } - -+#if !defined(ANGLE_PLATFORM_WINRT) - HWND window = (HWND)win; - - if (!IsWindow(window)) - { - return egl::error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } -+#endif - -- return display->createWindowSurface(window, config, attrib_list); -+ return display->createWindowSurface(win, config, attrib_list); - } - - EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) -diff --git a/src/3rdparty/angle/src/libEGL/main.cpp b/src/3rdparty/angle/src/libEGL/main.cpp -index 8a1baef..e74737e 100644 ---- a/src/3rdparty/angle/src/libEGL/main.cpp -+++ b/src/3rdparty/angle/src/libEGL/main.cpp -@@ -11,6 +11,9 @@ - #include "common/debug.h" - #include "common/tls.h" - -+#if defined(ANGLE_PLATFORM_WINRT) -+__declspec(thread) -+#endif - static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; - - namespace egl -@@ -18,6 +21,12 @@ namespace egl - - Current *AllocateCurrent() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (currentTLS == TLS_OUT_OF_INDEXES) -+ { -+ currentTLS = CreateTLSIndex(); -+ } -+#endif - ASSERT(currentTLS != TLS_OUT_OF_INDEXES); - if (currentTLS == TLS_OUT_OF_INDEXES) - { -@@ -42,6 +51,12 @@ Current *AllocateCurrent() - - void DeallocateCurrent() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (currentTLS == TLS_OUT_OF_INDEXES) -+ { -+ return; -+ } -+#endif - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - SafeDelete(current); - SetTLSValue(currentTLS, NULL); -@@ -72,6 +87,10 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - } +-#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP /* Windows Store */ ++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */ + #include ++typedef IInspectable* EGLNativeDisplayType; + typedef IInspectable* EGLNativeWindowType; + #else ++typedef HDC EGLNativeDisplayType; + typedef HWND EGLNativeWindowType; #endif -+#if defined(ANGLE_PLATFORM_WINRT) // On WinRT, don't handle TLS from DllMain -+ return DisableThreadLibraryCalls(instance); -+#endif -+ - currentTLS = CreateTLSIndex(); - if (currentTLS == TLS_OUT_OF_INDEXES) - { -@@ -86,7 +105,9 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - break; - case DLL_THREAD_DETACH: - { -+#if !defined(ANGLE_PLATFORM_WINRT) - egl::DeallocateCurrent(); -+#endif - } - break; - case DLL_PROCESS_DETACH: -diff --git a/src/3rdparty/angle/src/libGLESv2/main.cpp b/src/3rdparty/angle/src/libGLESv2/main.cpp -index 1c577bc..51447e2 100644 ---- a/src/3rdparty/angle/src/libGLESv2/main.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/main.cpp -@@ -11,6 +11,9 @@ - - #include "common/tls.h" - -+#if defined(ANGLE_PLATFORM_WINRT) -+__declspec(thread) -+#endif - static TLSIndex currentTLS = TLS_OUT_OF_INDEXES; - - namespace gl -@@ -18,6 +21,12 @@ namespace gl - - Current *AllocateCurrent() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (currentTLS == TLS_OUT_OF_INDEXES) -+ { -+ currentTLS = CreateTLSIndex(); -+ } -+#endif - ASSERT(currentTLS != TLS_OUT_OF_INDEXES); - if (currentTLS == TLS_OUT_OF_INDEXES) - { -@@ -39,6 +48,12 @@ Current *AllocateCurrent() - - void DeallocateCurrent() - { -+#if defined(ANGLE_PLATFORM_WINRT) -+ if (currentTLS == TLS_OUT_OF_INDEXES) -+ { -+ return; -+ } -+#endif - Current *current = reinterpret_cast(GetTLSValue(currentTLS)); - SafeDelete(current); - SetTLSValue(currentTLS, NULL); -@@ -54,6 +69,9 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - { - case DLL_PROCESS_ATTACH: - { -+#if defined(ANGLE_PLATFORM_WINRT) // On WinRT, don't handle TLS from DllMain -+ return DisableThreadLibraryCalls(instance); -+#endif - currentTLS = CreateTLSIndex(); - if (currentTLS == TLS_OUT_OF_INDEXES) - { -@@ -73,8 +91,10 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved - break; - case DLL_PROCESS_DETACH: - { -+#if !defined(ANGLE_PLATFORM_WINRT) - gl::DeallocateCurrent(); - DestroyTLSIndex(currentTLS); -+#endif - } - break; - default: -diff --git a/src/3rdparty/angle/src/libGLESv2/main.h b/src/3rdparty/angle/src/libGLESv2/main.h -index 684c302..c30ad33 100644 ---- a/src/3rdparty/angle/src/libGLESv2/main.h -+++ b/src/3rdparty/angle/src/libGLESv2/main.h -@@ -14,6 +14,10 @@ - #include - #include - -+#ifndef Sleep -+#define Sleep(ms) WaitForSingleObjectEx(GetCurrentThread(), ms, FALSE) -+#endif -+ - namespace egl - { - class Display; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h -index 7adbea2..b224974 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/Renderer.h -@@ -107,7 +107,7 @@ class Renderer - - virtual void sync(bool block) = 0; - -- virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; -+ virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) = 0; - - virtual gl::Error generateSwizzle(gl::Texture *texture) = 0; - virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler) = 0; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -index 12be9b3..1ec702f 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/SwapChain.h -@@ -15,14 +15,23 @@ - - #include - #include -+#include +diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h +index dc5fc8f..9e93aea 100644 +--- a/src/3rdparty/angle/src/common/NativeWindow.h ++++ b/src/3rdparty/angle/src/common/NativeWindow.h +@@ -44,10 +44,11 @@ typedef IDXGIFactory DXGIFactory; namespace rx { - -+enum SwapFlags -+{ -+ SWAP_NORMAL = 0, -+ SWAP_ROTATE_90 = 1, -+ SWAP_ROTATE_270 = 2, -+ SWAP_ROTATE_180 = SWAP_ROTATE_90|SWAP_ROTATE_270, -+}; + - class SwapChain + class NativeWindow { - public: -- SwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) -+ SwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) - : mWindow(window), mShareHandle(shareHandle), mBackBufferFormat(backBufferFormat), mDepthBufferFormat(depthBufferFormat) - { - } -@@ -31,13 +40,13 @@ class SwapChain +- public: +- explicit NativeWindow(EGLNativeWindowType window); ++public: ++ explicit NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display); - virtual EGLint resize(EGLint backbufferWidth, EGLint backbufferSize) = 0; - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval) = 0; -- virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height) = 0; -+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) = 0; - virtual void recreate() = 0; + bool initialize(); + bool getClientRect(LPRECT rect); +@@ -58,9 +59,11 @@ class NativeWindow + DXGISwapChain** swapChain); - virtual HANDLE getShareHandle() {return mShareHandle;}; + inline EGLNativeWindowType getNativeWindow() const { return mWindow; } ++ inline EGLNativeDisplayType getNativeDisplay() const { return mDisplay; } - protected: -- const HWND mWindow; // Window that the surface is created for. -+ const EGLNativeWindowType mWindow; // Window that the surface is created for. - const GLenum mBackBufferFormat; - const GLenum mDepthBufferFormat; + private: + EGLNativeWindowType mWindow; ++ EGLNativeDisplayType mDisplay; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -index 5715d5f..d013197 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp -@@ -9,6 +9,7 @@ - #include "libGLESv2/main.h" + #if defined(ANGLE_ENABLE_WINDOWS_STORE) + std::shared_ptr mImpl; +diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h +index cd12dba..0065ec7 100644 +--- a/src/3rdparty/angle/src/common/platform.h ++++ b/src/3rdparty/angle/src/common/platform.h +@@ -34,7 +34,7 @@ + #endif - #include "common/utilities.h" -+#include "common/platform.h" - - #if defined(__MINGW32__) && !defined(D3DCOMPILER_DLL) - -@@ -45,11 +46,7 @@ HLSLCompiler::~HLSLCompiler() - - bool HLSLCompiler::initialize() - { --<<<<<<< HEAD -- TRACE_EVENT0("gpu", "initializeCompiler"); --======= - #if !defined(ANGLE_PLATFORM_WINRT) -->>>>>>> 429814a... ANGLE: remove event tracing - #if defined(ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES) - // Find a D3DCompiler module that had already been loaded based on a predefined list of versions. - static const char *d3dCompilerNames[] = ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES; -@@ -94,7 +91,9 @@ bool HLSLCompiler::initialize() - - mD3DCompileFunc = reinterpret_cast(GetProcAddress(mD3DCompilerModule, "D3DCompile")); - ASSERT(mD3DCompileFunc); -- -+#else -+ mD3DCompileFunc = reinterpret_cast(&D3DCompile); -+#endif - return mD3DCompileFunc != NULL; + #ifdef ANGLE_PLATFORM_WINDOWS +-# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP ++# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + # define ANGLE_ENABLE_WINDOWS_STORE 1 + # endif + # ifndef STRICT +@@ -67,7 +67,9 @@ + # if defined(ANGLE_ENABLE_WINDOWS_STORE) + # include + # if defined(_DEBUG) ++# if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + # include ++# endif + # include + # endif + # endif +diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +index aa2bfa4..2440747 100644 +--- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +@@ -16,7 +16,7 @@ bool IsValidEGLNativeWindowType(EGLNativeWindowType window) + return (IsWindow(window) == TRUE); } -@@ -111,7 +110,9 @@ void HLSLCompiler::release() - ShaderBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const char *hlsl, const char *profile, - const UINT optimizationFlags[], const char *flagNames[], int attempts) const +-NativeWindow::NativeWindow(EGLNativeWindowType window) : mWindow(window) ++NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) : mWindow(window), mDisplay(display) { -+#if !defined(ANGLE_PLATFORM_WINRT) - ASSERT(mD3DCompilerModule && mD3DCompileFunc); -+#endif + } - if (!hlsl) +diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp +index 0e63fa5..9b65c15 100644 +--- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.cpp +@@ -6,21 +6,25 @@ + + // CoreWindowNativeWindow.cpp: NativeWindow for managing ICoreWindow native window types. + +-#include ++#include + #include "common/winrt/CoreWindowNativeWindow.h" + using namespace ABI::Windows::Foundation::Collections; + + namespace rx + { ++ ++typedef ITypedEventHandler SizeChangedHandler; ++ + CoreWindowNativeWindow::~CoreWindowNativeWindow() + { + unregisterForSizeChangeEvents(); + } + +-bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) ++bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) + { + ComPtr props = propertySet; + ComPtr win = window; ++ ComPtr displayInformation = display; + SIZE swapChainSize = {}; + bool swapChainSizeSpecified = false; + HRESULT result = S_OK; +@@ -47,6 +51,29 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet + + if (SUCCEEDED(result)) { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index ed880c3..0bb7489 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -6,6 +6,7 @@ - - // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer. - -+#include "common/platform.h" - #include "libGLESv2/main.h" - #include "libGLESv2/Buffer.h" - #include "libGLESv2/FramebufferAttachment.h" -@@ -135,6 +136,7 @@ EGLint Renderer11::initialize() - return EGL_NOT_INITIALIZED; - } - -+#if !defined(ANGLE_PLATFORM_WINRT) - mDxgiModule = LoadLibrary(TEXT("dxgi.dll")); - mD3d11Module = LoadLibrary(TEXT("d3d11.dll")); - -@@ -153,6 +155,7 @@ EGLint Renderer11::initialize() - ERR("Could not retrieve D3D11CreateDevice address - aborting!\n"); - return EGL_NOT_INITIALIZED; - } ++ result = displayInformation.As(&mDisplayInformation); ++ } ++ ++ if (SUCCEEDED(result)) ++ { ++#if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP ++ ComPtr displayInformation2; ++ result = mDisplayInformation.As(&displayInformation2); ++ ASSERT(SUCCEEDED(result)); ++ ++ result = displayInformation2->get_RawPixelsPerViewPixel(&mScaleFactor); ++ ASSERT(SUCCEEDED(result)); ++#else ++ ABI::Windows::Graphics::Display::ResolutionScale resolutionScale; ++ result = mDisplayInformation->get_ResolutionScale(&resolutionScale); ++ ASSERT(SUCCEEDED(result)); ++ ++ mScaleFactor = DOUBLE(resolutionScale) / 100.0; +#endif - - D3D_FEATURE_LEVEL featureLevels[] = - { -@@ -207,7 +210,7 @@ EGLint Renderer11::initialize() ++ } ++ ++ if (SUCCEEDED(result)) ++ { + // If a swapchain size is specfied, then the automatic resize + // behaviors implemented by the host should be disabled. The swapchain + // will be still be scaled when being rendered to fit the bounds +@@ -60,7 +87,14 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet + } + else + { +- result = GetCoreWindowSizeInPixels(mCoreWindow, &mClientRect); ++ ABI::Windows::Foundation::Rect rect; ++ HRESULT result = mCoreWindow->get_Bounds(&rect); ++ if (SUCCEEDED(result)) ++ { ++ LONG width = std::floor(rect.Width * mScaleFactor + 0.5); ++ LONG height = std::floor(rect.Height * mScaleFactor + 0.5); ++ mClientRect = { 0, 0, width, height }; ++ } } } --#if !ANGLE_SKIP_DXGI_1_2_CHECK -+#if !ANGLE_SKIP_DXGI_1_2_CHECK && !defined(ANGLE_PLATFORM_WINRT) - // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. - // The easiest way to check is to query for a IDXGIDevice2. - bool requireDXGI1_2 = false; -@@ -237,8 +240,12 @@ EGLint Renderer11::initialize() - } - #endif +@@ -76,12 +110,8 @@ bool CoreWindowNativeWindow::initialize(EGLNativeWindowType window, IPropertySet -+#if !defined(ANGLE_PLATFORM_WINRT) - IDXGIDevice *dxgiDevice = NULL; -- result = mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice); -+#else -+ IDXGIDevice1 *dxgiDevice = NULL; -+#endif -+ result = mDevice->QueryInterface(IID_PPV_ARGS(&dxgiDevice)); - - if (FAILED(result)) - { -@@ -408,7 +415,7 @@ void Renderer11::sync(bool block) - } - } - --SwapChain *Renderer11::createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) -+SwapChain *Renderer11::createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat) + bool CoreWindowNativeWindow::registerForSizeChangeEvents() { - return new rx::SwapChain11(this, window, shareHandle, backBufferFormat, depthBufferFormat); +- ComPtr sizeChangedHandler; +- HRESULT result = Microsoft::WRL::MakeAndInitialize(sizeChangedHandler.ReleaseAndGetAddressOf(), this->shared_from_this()); +- if (SUCCEEDED(result)) +- { +- result = mCoreWindow->add_SizeChanged(sizeChangedHandler.Get(), &mSizeChangedEventToken); +- } ++ HRESULT result = mCoreWindow->add_SizeChanged(Callback(this, &CoreWindowNativeWindow::onSizeChanged).Get(), ++ &mSizeChangedEventToken); + + if (SUCCEEDED(result)) + { +@@ -126,7 +156,7 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor + if (SUCCEEDED(result)) + { + +-#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) // This block is disabled for Qt applications, as the resize events are expected + // Test if swapchain supports resize. On Windows Phone devices, this will return DXGI_ERROR_UNSUPPORTED. On + // other devices DXGI_ERROR_INVALID_CALL should be returned because the combination of flags passed + // (DXGI_SWAP_CHAIN_FLAG_NONPREROTATED | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) are invalid flag combinations. +@@ -152,36 +182,19 @@ HRESULT CoreWindowNativeWindow::createSwapChain(ID3D11Device *device, DXGIFactor + return result; } + +-HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize) ++// Basically, this shouldn't be used on Phone ++HRESULT CoreWindowNativeWindow::onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *e) + { +- ABI::Windows::Foundation::Rect bounds; +- HRESULT result = coreWindow->get_Bounds(&bounds); +- if (SUCCEEDED(result)) ++ ABI::Windows::Foundation::Size size; ++ if (SUCCEEDED(e->get_Size(&size))) + { +- *windowSize = { 0, 0, ConvertDipsToPixels(bounds.Width), ConvertDipsToPixels(bounds.Height) }; ++ SIZE windowSizeInPixels = { ++ std::floor(size.Width * mScaleFactor + 0.5), ++ std::floor(size.Height * mScaleFactor + 0.5) ++ }; ++ setNewClientSize(windowSizeInPixels); + } + +- return result; +-} +- +-static float GetLogicalDpi() +-{ +- ComPtr displayProperties; +- float dpi = 96.0f; +- +- if (SUCCEEDED(GetActivationFactory(HStringReference(RuntimeClass_Windows_Graphics_Display_DisplayProperties).Get(), displayProperties.GetAddressOf()))) +- { +- if (SUCCEEDED(displayProperties->get_LogicalDpi(&dpi))) +- { +- return dpi; +- } +- } +- return dpi; +-} +- +-long ConvertDipsToPixels(float dips) +-{ +- static const float dipsPerInch = 96.0f; +- return lround((dips * GetLogicalDpi() / dipsPerInch)); ++ return S_OK; + } + } +diff --git a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h +index 0c6222d..1c55124 100644 +--- a/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h ++++ b/src/3rdparty/angle/src/common/winrt/CoreWindowNativeWindow.h +@@ -11,67 +11,29 @@ + + #include "common/winrt/InspectableNativeWindow.h" + #include +- +-typedef ABI::Windows::Foundation::__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t IWindowSizeChangedEventHandler; ++#include + + namespace rx + { +-long ConvertDipsToPixels(float dips); + + class CoreWindowNativeWindow : public InspectableNativeWindow, public std::enable_shared_from_this + { + public: + ~CoreWindowNativeWindow(); + +- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); ++ bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); + + private: ++ HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); ++ + ComPtr mCoreWindow; ++ ComPtr mDisplayInformation; + ComPtr> mPropertyMap; + }; + +-[uuid(7F924F66-EBAE-40E5-A10B-B8F35E245190)] +-class CoreWindowSizeChangedHandler : +- public Microsoft::WRL::RuntimeClass, IWindowSizeChangedEventHandler> +-{ +- public: +- CoreWindowSizeChangedHandler() { } +- HRESULT RuntimeClassInitialize(std::shared_ptr host) +- { +- if (!host) +- { +- return E_INVALIDARG; +- } +- +- mHost = host; +- return S_OK; +- } +- +- // IWindowSizeChangedEventHandler +- IFACEMETHOD(Invoke)(ABI::Windows::UI::Core::ICoreWindow *sender, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *sizeChangedEventArgs) +- { +- std::shared_ptr host = mHost.lock(); +- if (host) +- { +- ABI::Windows::Foundation::Size windowSize; +- if (SUCCEEDED(sizeChangedEventArgs->get_Size(&windowSize))) +- { +- SIZE windowSizeInPixels = { ConvertDipsToPixels(windowSize.Width), ConvertDipsToPixels(windowSize.Height) }; +- host->setNewClientSize(windowSizeInPixels); +- } +- } +- +- return S_OK; +- } +- +- private: +- std::weak_ptr mHost; +-}; +- +-HRESULT GetCoreWindowSizeInPixels(const ComPtr& coreWindow, RECT *windowSize); + } + + #endif // COMMON_WINRT_COREWINDOWNATIVEWINDOW_H_ +diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp +index c062a48..0589f6d 100644 +--- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.cpp +@@ -11,9 +11,9 @@ + + namespace rx + { +-NativeWindow::NativeWindow(EGLNativeWindowType window) ++NativeWindow::NativeWindow(EGLNativeWindowType window, EGLNativeDisplayType display) ++ : mWindow(window), mDisplay(display) + { +- mWindow = window; + } + + bool NativeWindow::initialize() +@@ -40,7 +40,7 @@ bool NativeWindow::initialize() + mImpl = std::make_shared(); + if (mImpl) + { +- return mImpl->initialize(mWindow, propertySet.Get()); ++ return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); + } + } + else if (IsSwapChainPanel(mWindow, &swapChainPanel)) +@@ -48,7 +48,7 @@ bool NativeWindow::initialize() + mImpl = std::make_shared(); + if (mImpl) + { +- return mImpl->initialize(mWindow, propertySet.Get()); ++ return mImpl->initialize(mWindow, mDisplay, propertySet.Get()); + } + } + else +diff --git a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h +index c625348..402941a 100644 +--- a/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h ++++ b/src/3rdparty/angle/src/common/winrt/InspectableNativeWindow.h +@@ -32,13 +32,14 @@ class InspectableNativeWindow + mRequiresSwapChainScaling(false), + mClientRectChanged(false), + mClientRect({0,0,0,0}), +- mNewClientRect({0,0,0,0}) ++ mNewClientRect({0,0,0,0}), ++ mScaleFactor(1.0) + { + mSizeChangedEventToken.value = 0; + } + virtual ~InspectableNativeWindow(){} + +- virtual bool initialize(EGLNativeWindowType window, IPropertySet *propertySet) = 0; ++ virtual bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) = 0; + virtual HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain) = 0; + virtual bool registerForSizeChangeEvents() = 0; + virtual void unregisterForSizeChangeEvents() = 0; +@@ -49,6 +50,7 @@ class InspectableNativeWindow + if (mClientRectChanged && mSupportsSwapChainResize) + { + mClientRect = mNewClientRect; ++ mClientRectChanged = false; + } + + *rect = mClientRect; +@@ -76,6 +78,7 @@ protected: + RECT mClientRect; + RECT mNewClientRect; + bool mClientRectChanged; ++ DOUBLE mScaleFactor; + + EventRegistrationToken mSizeChangedEventToken; + }; +diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp +index 4e4fb6d..268dfbd 100644 +--- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.cpp +@@ -18,7 +18,7 @@ SwapChainPanelNativeWindow::~SwapChainPanelNativeWindow() + unregisterForSizeChangeEvents(); + } + +-bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, IPropertySet *propertySet) ++bool SwapChainPanelNativeWindow::initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet) + { + ComPtr props = propertySet; + ComPtr win = window; +diff --git a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h +index e88f554..5bbf274 100644 +--- a/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h ++++ b/src/3rdparty/angle/src/common/winrt/SwapChainPanelNativeWindow.h +@@ -18,7 +18,7 @@ class SwapChainPanelNativeWindow : public InspectableNativeWindow, public std::e + public: + ~SwapChainPanelNativeWindow(); + +- bool initialize(EGLNativeWindowType window, IPropertySet *propertySet); ++ bool initialize(EGLNativeWindowType window, EGLNativeDisplayType display, IPropertySet *propertySet); + bool registerForSizeChangeEvents(); + void unregisterForSizeChangeEvents(); + HRESULT createSwapChain(ID3D11Device *device, DXGIFactory *factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain **swapChain); +diff --git a/src/3rdparty/angle/src/libEGL/Display.h b/src/3rdparty/angle/src/libEGL/Display.h +index 378323a..b3ffcc8 100644 +--- a/src/3rdparty/angle/src/libEGL/Display.h ++++ b/src/3rdparty/angle/src/libEGL/Display.h +@@ -67,6 +67,7 @@ class Display + + const char *getExtensionString() const; + const char *getVendorString() const; ++ EGLNativeDisplayType getDisplayId() const { return mDisplayId; } + + private: + DISALLOW_COPY_AND_ASSIGN(Display); +diff --git a/src/3rdparty/angle/src/libEGL/Surface.cpp b/src/3rdparty/angle/src/libEGL/Surface.cpp +index 3414656..b664a85 100644 +--- a/src/3rdparty/angle/src/libEGL/Surface.cpp ++++ b/src/3rdparty/angle/src/libEGL/Surface.cpp +@@ -31,7 +31,7 @@ namespace egl + { + + Surface::Surface(Display *display, const Config *config, EGLNativeWindowType window, EGLint fixedSize, EGLint width, EGLint height, EGLint postSubBufferSupported) +- : mDisplay(display), mConfig(config), mNativeWindow(window), mPostSubBufferSupported(postSubBufferSupported) ++ : mDisplay(display), mConfig(config), mNativeWindow(window, display->getDisplayId()), mPostSubBufferSupported(postSubBufferSupported) + { + //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) + mRenderer = static_cast(mDisplay->getRenderer()); +@@ -47,6 +47,8 @@ Surface::Surface(Display *display, const Config *config, EGLNativeWindowType win + mSwapInterval = -1; + mWidth = width; + mHeight = height; ++ mFixedWidth = mWidth; ++ mFixedHeight = mHeight; + setSwapInterval(1); + mFixedSize = fixedSize; + +@@ -54,7 +56,7 @@ Surface::Surface(Display *display, const Config *config, EGLNativeWindowType win + } + + Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType) +- : mDisplay(display), mNativeWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) ++ : mDisplay(display), mNativeWindow(NULL, NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height), mPostSubBufferSupported(EGL_FALSE) + { + //TODO(jmadill): MANGLE refactor. (note, can't call makeRendererD3D because of dll export issues) + mRenderer = static_cast(mDisplay->getRenderer()); +@@ -71,6 +73,8 @@ Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGL + setSwapInterval(1); + // This constructor is for offscreen surfaces, which are always fixed-size. + mFixedSize = EGL_TRUE; ++ mFixedWidth = mWidth; ++ mFixedHeight = mHeight; + } + + Surface::~Surface() +@@ -157,10 +161,13 @@ Error Surface::resetSwapChain() + + Error Surface::resizeSwapChain(int backbufferWidth, int backbufferHeight) + { +- ASSERT(backbufferWidth >= 0 && backbufferHeight >= 0); + ASSERT(mSwapChain); + +- EGLint status = mSwapChain->resize(std::max(1, backbufferWidth), std::max(1, backbufferHeight)); ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) ++ backbufferWidth = std::max(1, backbufferWidth); ++ backbufferHeight = std::max(1, backbufferHeight); ++#endif ++ EGLint status = mSwapChain->resize(backbufferWidth, backbufferHeight); + + if (status == EGL_CONTEXT_LOST) + { +@@ -209,14 +216,14 @@ Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + return Error(EGL_SUCCESS); + } + +- if (x + width > mWidth) ++ if (x + width > abs(mWidth)) + { +- width = mWidth - x; ++ width = abs(mWidth) - x; + } + +- if (y + height > mHeight) ++ if (y + height > abs(mHeight)) + { +- height = mHeight - y; ++ height = abs(mHeight) - y; + } + + if (width == 0 || height == 0) +@@ -224,6 +231,9 @@ Error Surface::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + return Error(EGL_SUCCESS); + } + ++ ASSERT(width > 0); ++ ASSERT(height > 0); ++ + EGLint status = mSwapChain->swapRect(x, y, width, height); + + if (status == EGL_CONTEXT_LOST) +@@ -352,6 +362,13 @@ bool Surface::checkForOutOfDateSwapChain() + sizeDirty = clientWidth != getWidth() || clientHeight != getHeight(); + } + ++ if (mFixedSize && (mWidth != mFixedWidth || mHeight != mFixedHeight)) ++ { ++ clientWidth = mFixedWidth; ++ clientHeight = mFixedHeight; ++ sizeDirty = true; ++ } ++ + bool wasDirty = (mSwapIntervalDirty || sizeDirty); + + if (mSwapIntervalDirty) +@@ -378,7 +395,7 @@ bool Surface::checkForOutOfDateSwapChain() + + Error Surface::swap() + { +- return swapRect(0, 0, mWidth, mHeight); ++ return swapRect(0, 0, abs(mWidth), abs(mHeight)); + } + + Error Surface::postSubBuffer(EGLint x, EGLint y, EGLint width, EGLint height) +@@ -471,6 +488,16 @@ EGLint Surface::isFixedSize() const + return mFixedSize; + } + ++void Surface::setFixedWidth(EGLint width) ++{ ++ mFixedWidth = width; ++} ++ ++void Surface::setFixedHeight(EGLint height) ++{ ++ mFixedHeight = height; ++} ++ + EGLenum Surface::getFormat() const + { + return mConfig->mRenderTargetFormat; +diff --git a/src/3rdparty/angle/src/libEGL/Surface.h b/src/3rdparty/angle/src/libEGL/Surface.h +index 662fe21..46382d0 100644 +--- a/src/3rdparty/angle/src/libEGL/Surface.h ++++ b/src/3rdparty/angle/src/libEGL/Surface.h +@@ -70,6 +70,8 @@ class Surface + virtual gl::Texture2D *getBoundTexture() const; + + EGLint isFixedSize() const; ++ void setFixedWidth(EGLint width); ++ void setFixedHeight(EGLint height); + + private: + DISALLOW_COPY_AND_ASSIGN(Surface); +@@ -91,6 +93,8 @@ class Surface + const egl::Config *mConfig; // EGL config surface was created with + EGLint mHeight; // Height of surface + EGLint mWidth; // Width of surface ++ EGLint mFixedHeight; // Pending height of the surface ++ EGLint mFixedWidth; // Pending width of the surface + // EGLint horizontalResolution; // Horizontal dot pitch + // EGLint verticalResolution; // Vertical dot pitch + // EGLBoolean largestPBuffer; // If true, create largest pbuffer possible +diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp +index 6110698..dc20d85 100644 +--- a/src/3rdparty/angle/src/libEGL/libEGL.cpp ++++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp +@@ -706,6 +706,26 @@ EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint + return EGL_FALSE; + } + ++ switch (attribute) ++ { ++ case EGL_WIDTH: ++ if (!eglSurface->isFixedSize() || !value) { ++ recordError(egl::Error(EGL_BAD_PARAMETER)); ++ return EGL_FALSE; ++ } ++ eglSurface->setFixedWidth(value); ++ return EGL_TRUE; ++ case EGL_HEIGHT: ++ if (!eglSurface->isFixedSize() || !value) { ++ recordError(egl::Error(EGL_BAD_PARAMETER)); ++ return EGL_FALSE; ++ } ++ eglSurface->setFixedHeight(value); ++ return EGL_TRUE; ++ default: ++ break; ++ } ++ + UNIMPLEMENTED(); // FIXME + + recordError(egl::Error(EGL_SUCCESS)); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -index d309f14..b86f5e5 100644 +index 1655f1d..c789cae 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -@@ -57,7 +57,7 @@ class Renderer11 : public Renderer - - virtual void sync(bool block); - -- virtual SwapChain *createSwapChain(HWND window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); -+ virtual SwapChain *createSwapChain(EGLNativeWindowType window, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat); - - virtual gl::Error generateSwizzle(gl::Texture *texture); - virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler); -@@ -222,7 +222,7 @@ class Renderer11 : public Renderer +@@ -231,7 +231,7 @@ class Renderer11 : public RendererD3D HMODULE mD3d11Module; HMODULE mDxgiModule; - HDC mDc; + EGLNativeDisplayType mDc; - EGLint mRequestedDisplay; + std::vector mAvailableFeatureLevels; + D3D_DRIVER_TYPE mDriverType; - HLSLCompiler mCompiler; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -index 50dae4e..787c511 100644 +index 834b7bd..52c8a81 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -@@ -6,6 +6,7 @@ - - // SwapChain11.cpp: Implements a back-end specific class for the D3D11 swap chain. - -+#include "common/platform.h" - #include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h" - #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" - #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" -@@ -18,7 +19,7 @@ - namespace rx - { - --SwapChain11::SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle, -+SwapChain11::SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat) - : mRenderer(renderer), SwapChain(window, shareHandle, backBufferFormat, depthBufferFormat) - { -@@ -38,6 +39,8 @@ SwapChain11::SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle, +@@ -42,6 +42,8 @@ SwapChain11::SwapChain11(Renderer11 *renderer, NativeWindow nativeWindow, HANDLE mPassThroughPS = NULL; mWidth = -1; mHeight = -1; -+ mViewportWidth = -1; -+ mViewportHeight = -1; ++ mRotateL = false; ++ mRotateR = false; mSwapInterval = 0; mAppCreatedShareHandle = mShareHandle != NULL; mPassThroughResourcesInit = false; -@@ -92,6 +95,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - ASSERT(backbufferHeight >= 1); +@@ -92,10 +94,11 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + ASSERT(device != NULL); + + // D3D11 does not allow zero size textures +- ASSERT(backbufferWidth >= 1); +- ASSERT(backbufferHeight >= 1); ++ ASSERT(backbufferWidth != 0); ++ ASSERT(backbufferHeight != 0); // Preserve the render target content -+#if !defined(ANGLE_PLATFORM_WINRT) ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) ID3D11Texture2D *previousOffscreenTexture = mOffscreenTexture; if (previousOffscreenTexture) { -@@ -99,6 +103,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei +@@ -103,6 +106,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei } const int previousWidth = mWidth; const int previousHeight = mHeight; @@ -1128,112 +675,107 @@ index 50dae4e..787c511 100644 releaseOffscreenTexture(); -@@ -281,7 +286,12 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei +@@ -136,8 +140,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; + mOffscreenTexture->GetDesc(&offscreenTextureDesc); +- if (offscreenTextureDesc.Width != (UINT)backbufferWidth || +- offscreenTextureDesc.Height != (UINT)backbufferHeight || ++ if (offscreenTextureDesc.Width != UINT(abs(backbufferWidth)) || ++ offscreenTextureDesc.Height != UINT(abs(backbufferHeight)) || + offscreenTextureDesc.Format != backbufferFormatInfo.texFormat || + offscreenTextureDesc.MipLevels != 1 || + offscreenTextureDesc.ArraySize != 1) +@@ -152,8 +156,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + const bool useSharedResource = !mNativeWindow.getNativeWindow() && mRenderer->getShareHandleSupport(); + + D3D11_TEXTURE2D_DESC offscreenTextureDesc = {0}; +- offscreenTextureDesc.Width = backbufferWidth; +- offscreenTextureDesc.Height = backbufferHeight; ++ offscreenTextureDesc.Width = abs(backbufferWidth); ++ offscreenTextureDesc.Height = abs(backbufferHeight); + offscreenTextureDesc.Format = backbufferFormatInfo.texFormat; + offscreenTextureDesc.MipLevels = 1; + offscreenTextureDesc.ArraySize = 1; +@@ -233,8 +237,8 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + if (mDepthBufferFormat != GL_NONE) + { + D3D11_TEXTURE2D_DESC depthStencilTextureDesc; +- depthStencilTextureDesc.Width = backbufferWidth; +- depthStencilTextureDesc.Height = backbufferHeight; ++ depthStencilTextureDesc.Width = abs(backbufferWidth); ++ depthStencilTextureDesc.Height = abs(backbufferHeight); + depthStencilTextureDesc.Format = depthBufferFormatInfo.texFormat; + depthStencilTextureDesc.MipLevels = 1; + depthStencilTextureDesc.ArraySize = 1; +@@ -286,6 +290,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei mWidth = backbufferWidth; mHeight = backbufferHeight; -+#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP -+ mViewportWidth = backbufferWidth; -+ mViewportHeight = backbufferHeight; -+#endif -+#if !defined(ANGLE_PLATFORM_WINRT) ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) if (previousOffscreenTexture != NULL) { D3D11_BOX sourceBox = {0}; -@@ -300,9 +310,10 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei - - if (mSwapChain) - { -- swapRect(0, 0, mWidth, mHeight); -+ swapRect(0, 0, mWidth, mHeight, SWAP_NORMAL); +@@ -307,6 +312,7 @@ EGLint SwapChain11::resetOffscreenTexture(int backbufferWidth, int backbufferHei + swapRect(0, 0, mWidth, mHeight); } } +#endif return EGL_SUCCESS; } -@@ -329,8 +340,15 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) +@@ -320,8 +326,16 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + return EGL_BAD_ACCESS; + } + ++ // Windows Phone works around the rotation limitation by using negative values for the swap chain size ++#if defined(ANGLE_ENABLE_WINDOWS_STORE) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) ++ mRotateL = backbufferWidth < 0; // Landscape/InvertedLandscape ++ mRotateR = backbufferHeight < 0; // InvertedPortrait/InvertedLandscape ++ backbufferWidth = abs(backbufferWidth); ++ backbufferHeight = abs(backbufferHeight); ++#endif ++ + // EGL allows creating a surface with 0x0 dimension, however, DXGI does not like 0x0 swapchains +- if (backbufferWidth < 1 || backbufferHeight < 1) ++ if (backbufferWidth == 0 || backbufferHeight == 0) + { + return EGL_SUCCESS; + } +@@ -329,6 +343,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) + // Can only call resize if we have already created our swap buffer and resources + ASSERT(mSwapChain && mBackBufferTexture && mBackBufferRTView); + ++#if !defined(ANGLE_ENABLE_WINDOWS_STORE) || (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) // The swap chain is not directly resized on Windows Phone + SafeRelease(mBackBufferTexture); SafeRelease(mBackBufferRTView); - // Resize swap chain -+ HRESULT result; -+#if !defined(ANGLE_PLATFORM_WINRT) || WINAPI_FAMILY==WINAPI_FAMILY_PC_APP // Windows phone swap chain is never resized, only the texture is -+#if !defined(ANGLE_PLATFORM_WINRT) -+ const int bufferCount = 1; -+#else -+ const int bufferCount = 2; -+#endif - const d3d11::TextureFormat &backbufferFormatInfo = d3d11::GetTextureFormatInfo(mBackBufferFormat); -- HRESULT result = mSwapChain->ResizeBuffers(1, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); -+ result = mSwapChain->ResizeBuffers(bufferCount, backbufferWidth, backbufferHeight, backbufferFormatInfo.texFormat, 0); - - if (FAILED(result)) +@@ -366,6 +381,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) { -@@ -346,6 +364,7 @@ EGLint SwapChain11::resize(EGLint backbufferWidth, EGLint backbufferHeight) - return EGL_BAD_ALLOC; - } + d3d11::SetDebugName(mBackBufferRTView, "Back buffer render target"); } +#endif - result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBufferTexture); - ASSERT(SUCCEEDED(result)); -@@ -399,6 +418,7 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap - - IDXGIFactory *factory = mRenderer->getDxgiFactory(); - -+#if !defined(ANGLE_PLATFORM_WINRT) - DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; - swapChainDesc.BufferDesc.Width = backbufferWidth; - swapChainDesc.BufferDesc.Height = backbufferHeight; -@@ -417,7 +437,37 @@ EGLint SwapChain11::reset(int backbufferWidth, int backbufferHeight, EGLint swap - swapChainDesc.Flags = 0; - - HRESULT result = factory->CreateSwapChain(device, &swapChainDesc, &mSwapChain); -+#else -+ IDXGIFactory2 *factory2; -+ HRESULT result = factory->QueryInterface(IID_PPV_ARGS(&factory2)); -+ ASSERT(SUCCEEDED(result)); -+ -+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; -+ swapChainDesc.Width = 0; -+ swapChainDesc.Height = 0; -+ swapChainDesc.Format = backbufferFormatInfo.texFormat; -+ swapChainDesc.SampleDesc.Count = 1; -+ swapChainDesc.SampleDesc.Quality = 0; -+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; -+ swapChainDesc.Stereo = FALSE; -+ swapChainDesc.Flags = 0; -+#if WINAPI_FAMILY==WINAPI_FAMILY_PC_APP -+ swapChainDesc.Scaling = DXGI_SCALING_NONE; -+ swapChainDesc.BufferCount = 2; -+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; -+#elif WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP -+ swapChainDesc.BufferCount = 1; -+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; -+#endif - -+ IDXGISwapChain1 *swapChain; -+ result = factory2->CreateSwapChainForCoreWindow(device, mWindow, &swapChainDesc, NULL, &swapChain); -+ mSwapChain = swapChain; -+ HRESULT hr = swapChain->GetDesc1(&swapChainDesc); -+ ASSERT(SUCCEEDED(hr)); -+ mViewportWidth = swapChainDesc.Width; -+ mViewportHeight = swapChainDesc.Height; -+#endif - if (FAILED(result)) - { - ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result); -@@ -513,7 +563,7 @@ void SwapChain11::initPassThroughResources() + return resetOffscreenTexture(backbufferWidth, backbufferHeight); } +@@ -512,16 +528,6 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + ID3D11Device *device = mRenderer->getDevice(); + ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); - // parameters should be validated/clamped by caller --EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) -+EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags) - { - if (!mSwapChain) - { -@@ -544,10 +594,13 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +- // Set vertices +- D3D11_MAPPED_SUBRESOURCE mappedResource; +- HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); +- if (FAILED(result)) +- { +- return EGL_BAD_ACCESS; +- } +- +- d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); +- + // Create a quad in homogeneous coordinates + float x1 = (x / float(mWidth)) * 2.0f - 1.0f; + float y1 = (y / float(mHeight)) * 2.0f - 1.0f; +@@ -533,10 +539,23 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) float u2 = (x + width) / float(mWidth); float v2 = (y + height) / float(mHeight); @@ -1241,8 +783,18 @@ index 50dae4e..787c511 100644 - d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, u1, v2); - d3d11::SetPositionTexCoordVertex(&vertices[2], x2, y1, u2, v1); - d3d11::SetPositionTexCoordVertex(&vertices[3], x2, y2, u2, v2); -+ const int rotateL = flags & SWAP_ROTATE_90; -+ const int rotateR = flags & SWAP_ROTATE_270; ++ const bool rotateL = mRotateL; ++ const bool rotateR = mRotateR; ++ ++ // Set vertices ++ D3D11_MAPPED_SUBRESOURCE mappedResource; ++ HRESULT result = deviceContext->Map(mQuadVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); ++ if (FAILED(result)) ++ { ++ return EGL_BAD_ACCESS; ++ } ++ ++ d3d11::PositionTexCoordVertex *vertices = static_cast(mappedResource.pData); + + d3d11::SetPositionTexCoordVertex(&vertices[0], x1, y1, rotateL ? u2 : u1, rotateR ? v2 : v1); + d3d11::SetPositionTexCoordVertex(&vertices[1], x1, y2, rotateR ? u2 : u1, rotateL ? v1 : v2); @@ -1251,72 +803,35 @@ index 50dae4e..787c511 100644 deviceContext->Unmap(mQuadVB, 0); -@@ -577,8 +630,8 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) +@@ -564,10 +583,11 @@ EGLint SwapChain11::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) + + // Set the viewport D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; +- viewport.TopLeftX = 0; +- viewport.TopLeftY = 0; - viewport.Width = mWidth; - viewport.Height = mHeight; -+ viewport.Width = mViewportWidth; -+ viewport.Height = mViewportHeight; ++ viewport.TopLeftX = 0.0f; ++ viewport.TopLeftY = 0.0f; ++ const bool invertViewport = (mRotateL || mRotateR) && !(mRotateL && mRotateR); ++ viewport.Width = FLOAT(invertViewport ? mHeight : mWidth); ++ viewport.Height = FLOAT(invertViewport ? mWidth : mHeight); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; deviceContext->RSSetViewports(1, &viewport); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h -index fb0afd7..b30b785 100644 +index 22401d8..77509ed 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.h -@@ -19,13 +19,13 @@ class Renderer11; - class SwapChain11 : public SwapChain - { - public: -- SwapChain11(Renderer11 *renderer, HWND window, HANDLE shareHandle, -+ SwapChain11(Renderer11 *renderer, EGLNativeWindowType window, HANDLE shareHandle, - GLenum backBufferFormat, GLenum depthBufferFormat); - virtual ~SwapChain11(); - - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); -- virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); -+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint flags); - virtual void recreate(); - - virtual ID3D11Texture2D *getOffscreenTexture(); @@ -52,6 +52,8 @@ class SwapChain11 : public SwapChain Renderer11 *mRenderer; EGLint mHeight; EGLint mWidth; -+ EGLint mViewportWidth; -+ EGLint mViewportHeight; ++ bool mRotateL; ++ bool mRotateR; bool mAppCreatedShareHandle; unsigned int mSwapInterval; bool mPassThroughResourcesInit; -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp -index f702b79..0aeaabb 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.cpp -@@ -238,7 +238,7 @@ EGLint SwapChain9::reset(int backbufferWidth, int backbufferHeight, EGLint swapI - } - - // parameters should be validated/clamped by caller --EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height) -+EGLint SwapChain9::swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint) - { - if (!mSwapChain) - { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h -index 16a62bd..4d756f8 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/SwapChain9.h -@@ -25,7 +25,7 @@ class SwapChain9 : public SwapChain - - EGLint resize(EGLint backbufferWidth, EGLint backbufferHeight); - virtual EGLint reset(EGLint backbufferWidth, EGLint backbufferHeight, EGLint swapInterval); -- virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height); -+ virtual EGLint swapRect(EGLint x, EGLint y, EGLint width, EGLint height, EGLint); - virtual void recreate(); - - virtual IDirect3DSurface9 *getRenderTarget(); -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch b/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch index 297d5adc84..dd2768cf3e 100644 --- a/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch +++ b/src/angle/patches/0010-ANGLE-Enable-D3D11-for-feature-level-9-cards.patch @@ -1,6 +1,6 @@ -From 0e8aa60332e17f284804dc1b89a9db5795a92ecb Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Wed, 17 Sep 2014 21:17:39 +0300 +From 829bf86c57357d3c8ec598b92fcfdb1849e84075 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Tue, 11 Nov 2014 17:11:54 +0200 Subject: [PATCH 10/16] ANGLE: Enable D3D11 for feature level 9 cards Enable use of ANGLE on lower-end hardware, such as Surface RT and @@ -8,23 +8,32 @@ Windows Phone 8. Change-Id: Ice536802e4eedc1d264abd0dd65960638fce59e4 --- - src/3rdparty/angle/src/libGLESv2/angletypes.cpp | 4 +- - .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 73 +++---- + src/3rdparty/angle/src/libGLESv2/angletypes.cpp | 6 +- + .../src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp | 69 ++++--- .../src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp | 4 +- - .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 8 +- - .../renderer/d3d/d3d11/PixelTransfer11.cpp | 7 +- - .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 209 +++++++++++++-------- + .../src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp | 7 +- + .../renderer/d3d/d3d11/PixelTransfer11.cpp | 9 +- + .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 226 +++++++++++++-------- .../src/libGLESv2/renderer/d3d/d3d11/Renderer11.h | 1 + - .../renderer/d3d/d3d11/TextureStorage11.cpp | 2 +- + .../renderer/d3d/d3d11/TextureStorage11.cpp | 4 +- .../libGLESv2/renderer/d3d/d3d11/formatutils11.cpp | 4 +- .../renderer/d3d/d3d11/renderer11_utils.cpp | 2 +- - 10 files changed, 190 insertions(+), 124 deletions(-) + 10 files changed, 208 insertions(+), 124 deletions(-) diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp -index 06618d5..bb6425d 100644 +index 6fd02e0..5a0cfc5 100644 --- a/src/3rdparty/angle/src/libGLESv2/angletypes.cpp +++ b/src/3rdparty/angle/src/libGLESv2/angletypes.cpp -@@ -22,8 +22,8 @@ SamplerState::SamplerState() +@@ -12,6 +12,8 @@ + #include "libGLESv2/State.h" + #include "libGLESv2/VertexArray.h" + ++#include ++ + namespace gl + { + +@@ -24,8 +26,8 @@ SamplerState::SamplerState() maxAnisotropy(1.0f), baseLevel(0), maxLevel(1000), @@ -36,28 +45,28 @@ index 06618d5..bb6425d 100644 compareFunc(GL_LEQUAL), swizzleRed(GL_RED), diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -index 72820a4..d43e65e 100644 +index 91e7552..06aea9b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Blit11.cpp -@@ -209,7 +209,7 @@ Blit11::Blit11(rx::Renderer11 *renderer) +@@ -209,7 +209,7 @@ Blit11::Blit11(Renderer11 *renderer) pointSamplerDesc.BorderColor[2] = 0.0f; pointSamplerDesc.BorderColor[3] = 0.0f; pointSamplerDesc.MinLOD = 0.0f; - pointSamplerDesc.MaxLOD = 0.0f; -+ pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; ++ pointSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; result = device->CreateSamplerState(&pointSamplerDesc, &mPointSampler); ASSERT(SUCCEEDED(result)); -@@ -228,7 +228,7 @@ Blit11::Blit11(rx::Renderer11 *renderer) +@@ -228,7 +228,7 @@ Blit11::Blit11(Renderer11 *renderer) linearSamplerDesc.BorderColor[2] = 0.0f; linearSamplerDesc.BorderColor[3] = 0.0f; linearSamplerDesc.MinLOD = 0.0f; - linearSamplerDesc.MaxLOD = 0.0f; -+ linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? FLT_MAX : 0.0f; ++ linearSamplerDesc.MaxLOD = mRenderer->isLevel9() ? D3D11_FLOAT32_MAX : 0.0f; result = device->CreateSamplerState(&linearSamplerDesc, &mLinearSampler); ASSERT(SUCCEEDED(result)); -@@ -290,28 +290,31 @@ Blit11::Blit11(rx::Renderer11 *renderer) +@@ -290,28 +290,31 @@ Blit11::Blit11(Renderer11 *renderer) ASSERT(SUCCEEDED(result)); d3d11::SetDebugName(mQuad2DVS, "Blit11 2D vertex shader"); @@ -76,14 +85,14 @@ index 72820a4..d43e65e 100644 - result = device->CreateInputLayout(quad3DLayout, ArraySize(quad3DLayout), g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), &mQuad3DIL); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad3DIL, "Blit11 3D input layout"); +- +- result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); +- ASSERT(SUCCEEDED(result)); +- d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); + result = device->CreatePixelShader(g_PS_PassthroughDepth2D, ArraySize(g_PS_PassthroughDepth2D), NULL, &mDepthPS); + ASSERT(SUCCEEDED(result)); + d3d11::SetDebugName(mDepthPS, "Blit11 2D depth pixel shader"); -- result = device->CreateVertexShader(g_VS_Passthrough3D, ArraySize(g_VS_Passthrough3D), NULL, &mQuad3DVS); -- ASSERT(SUCCEEDED(result)); -- d3d11::SetDebugName(mQuad3DVS, "Blit11 3D vertex shader"); -- - result = device->CreateGeometryShader(g_GS_Passthrough3D, ArraySize(g_GS_Passthrough3D), NULL, &mQuad3DGS); - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mQuad3DGS, "Renderer11 copy 3D texture geometry shader"); @@ -109,7 +118,7 @@ index 72820a4..d43e65e 100644 buildShaderMap(); -@@ -972,40 +975,44 @@ void Blit11::buildShaderMap() +@@ -970,22 +973,27 @@ void Blit11::buildShaderMap() ID3D11Device *device = mRenderer->getDevice(); add2DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA2D, "Blit11 2D RGBA pixel shader" )); @@ -145,19 +154,7 @@ index 72820a4..d43e65e 100644 add3DBlitShaderToMap(GL_RGBA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D RGBA pixel shader" )); add3DBlitShaderToMap(GL_RGBA_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DUI, "Blit11 3D UI RGBA pixel shader" )); add3DBlitShaderToMap(GL_RGBA_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGBA3DI, "Blit11 3D I RGBA pixel shader" )); - add3DBlitShaderToMap(GL_BGRA_EXT, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D BGRA pixel shader" )); - add3DBlitShaderToMap(GL_RGB, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3D, "Blit11 3D RGB pixel shader" )); -+ add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); - add3DBlitShaderToMap(GL_RGB_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRGB3DUI, "Blit11 3D RGB UI pixel shader" )); - add3DBlitShaderToMap(GL_RGB_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRGB3DI, "Blit11 3D RGB I pixel shader" )); -- add3DBlitShaderToMap(GL_RG, false, d3d11::CompilePS(device, g_PS_PassthroughRG3D, "Blit11 3D RG pixel shader" )); -+ add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); - add3DBlitShaderToMap(GL_RG_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughRG3DUI, "Blit11 3D RG UI pixel shader" )); - add3DBlitShaderToMap(GL_RG_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughRG3DI, "Blit11 3D RG I pixel shader" )); -- add3DBlitShaderToMap(GL_RED, false, d3d11::CompilePS(device, g_PS_PassthroughR3D, "Blit11 3D R pixel shader" )); - add3DBlitShaderToMap(GL_RED_INTEGER, false, d3d11::CompilePS(device, g_PS_PassthroughR3DUI, "Blit11 3D R UI pixel shader" )); - add3DBlitShaderToMap(GL_RED_INTEGER, true, d3d11::CompilePS(device, g_PS_PassthroughR3DI, "Blit11 3D R I pixel shader" )); - add3DBlitShaderToMap(GL_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughRGBA3D, "Blit11 3D alpha pixel shader" )); +@@ -1003,7 +1011,6 @@ void Blit11::buildShaderMap() add3DBlitShaderToMap(GL_LUMINANCE, false, d3d11::CompilePS(device, g_PS_PassthroughLum3D, "Blit11 3D luminance pixel shader" )); add3DBlitShaderToMap(GL_LUMINANCE_ALPHA, false, d3d11::CompilePS(device, g_PS_PassthroughLumAlpha3D, "Blit11 3D luminance alpha pixel shader")); @@ -166,22 +163,22 @@ index 72820a4..d43e65e 100644 addSwizzleShaderToMap(GL_INT, D3D_SRV_DIMENSION_TEXTURE2D, d3d11::CompilePS(device, g_PS_SwizzleI2D, "Blit11 2D I swizzle pixel shader" )); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp -index 43ce5ba..ecd4d46 100644 +index 2d5fa3c..5aab379 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Buffer11.cpp -@@ -747,7 +747,9 @@ void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Ren +@@ -753,7 +753,9 @@ void Buffer11::NativeBuffer11::fillBufferDesc(D3D11_BUFFER_DESC* bufferDesc, Ren case BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK: bufferDesc->Usage = D3D11_USAGE_DEFAULT; - bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT; + bufferDesc->BindFlags = D3D11_BIND_VERTEX_BUFFER; -+ if (!static_cast(renderer)->isLevel9()) ++ if (!renderer->isLevel9()) + bufferDesc->BindFlags |= D3D11_BIND_STREAM_OUTPUT; bufferDesc->CPUAccessFlags = 0; break; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp -index 5caa427..765d34f 100644 +index 4630762..7185a05 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Clear11.cpp @@ -104,7 +104,7 @@ Clear11::Clear11(Renderer11 *renderer) @@ -189,11 +186,11 @@ index 5caa427..765d34f 100644 rsDesc.DepthBiasClamp = 0.0f; rsDesc.SlopeScaledDepthBias = 0.0f; - rsDesc.DepthClipEnable = FALSE; -+ rsDesc.DepthClipEnable = mRenderer->isLevel9(); ++ rsDesc.DepthClipEnable = renderer->isLevel9(); rsDesc.ScissorEnable = FALSE; rsDesc.MultisampleEnable = FALSE; rsDesc.AntialiasedLineEnable = FALSE; -@@ -114,6 +114,12 @@ Clear11::Clear11(Renderer11 *renderer) +@@ -114,6 +114,11 @@ Clear11::Clear11(Renderer11 *renderer) d3d11::SetDebugName(mRasterizerState, "Clear11 masked clear rasterizer state"); mFloatClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_FLOAT, g_VS_ClearFloat, g_PS_ClearFloat); @@ -202,53 +199,63 @@ index 5caa427..765d34f 100644 + memset(&mIntClearShader, 0, sizeof(ClearShader)); + return; + } -+ mUintClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_UINT, g_VS_ClearUint, g_PS_ClearUint ); mIntClearShader = CreateClearShader(device, DXGI_FORMAT_R32G32B32A32_SINT, g_VS_ClearSint, g_PS_ClearSint ); } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -index edaafec..a4e84f9 100644 +index a4072d8..6a3d347 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/PixelTransfer11.cpp -@@ -88,13 +88,16 @@ PixelTransfer11::PixelTransfer11(Renderer11 *renderer) - ASSERT(SUCCEEDED(result)); - d3d11::SetDebugName(mParamsConstantBuffer, "PixelTransfer11 constant buffer"); +@@ -133,10 +133,13 @@ gl::Error PixelTransfer11::loadResources() + return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture vertex shader."); + } -+ StructZero(&mParamsData); -+ - // init shaders -+ if (mRenderer->isLevel9()) -+ return; -+ - mBufferToTextureVS = d3d11::CompileVS(device, g_VS_BufferToTexture, "BufferToTexture VS"); - mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); +- mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); +- if (!mBufferToTextureGS) ++ if (!mRenderer->isLevel9()) + { +- return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); ++ mBufferToTextureGS = d3d11::CompileGS(device, g_GS_BufferToTexture, "BufferToTexture GS"); ++ if (!mBufferToTextureGS) ++ { ++ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal buffer to texture geometry shader."); ++ } + } - buildShaderMap(); -- -- StructZero(&mParamsData); - } - - PixelTransfer11::~PixelTransfer11() + gl::Error error = buildShaderMap(); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index 0bb7489..b4b26a8 100644 +index ffc6cc9..f6ba930 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -162,6 +162,11 @@ EGLint Renderer11::initialize() - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, -+#if !defined(ANGLE_ENABLE_D3D9) -+ D3D_FEATURE_LEVEL_9_3, -+ D3D_FEATURE_LEVEL_9_2, -+ D3D_FEATURE_LEVEL_9_1, -+#endif - }; +@@ -153,6 +153,24 @@ Renderer11::Renderer11(egl::Display *display, EGLNativeDisplayType hDc, const eg + } + } - D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_HARDWARE; -@@ -1112,6 +1117,84 @@ gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, cons ++#if !defined(ANGLE_ENABLE_D3D9) ++ if (requestedMajorVersion == EGL_DONT_CARE || requestedMajorVersion >= 9) ++ { ++ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 3) ++ { ++ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_3); ++ } ++ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 2) ++ { ++ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_2); ++ } ++ if (requestedMinorVersion == EGL_DONT_CARE || requestedMinorVersion >= 1) ++ { ++ mAvailableFeatureLevels.push_back(D3D_FEATURE_LEVEL_9_1); ++ } ++ } ++#endif ++ + mDriverType = (attributes.get(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_FALSE) == EGL_TRUE) ? D3D_DRIVER_TYPE_WARP + : D3D_DRIVER_TYPE_HARDWARE; + } +@@ -1170,6 +1188,83 @@ gl::Error Renderer11::drawElements(GLenum mode, GLsizei count, GLenum type, cons + return gl::Error(GL_NO_ERROR); } } - +template +static void fillLineLoopIndices(GLenum type, GLsizei count, const GLvoid *indices, T *data) +{ @@ -326,12 +333,11 @@ index 0bb7489..b4b26a8 100644 + default: UNREACHABLE(); + } +} -+ + gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer) { - // Get the raw indices for an indexed draw -@@ -1123,10 +1206,13 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind - indices = static_cast(storage->getData()) + offset; +@@ -1189,10 +1284,13 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind + indices = bufferData + offset; } + // TODO: some level 9 hardware supports 32-bit indices; test and store support instead @@ -345,7 +351,7 @@ index 0bb7489..b4b26a8 100644 if (error.isError()) { SafeDelete(mLineLoopIB); -@@ -1137,7 +1223,8 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind +@@ -1203,7 +1301,8 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind // Checked by Renderer11::applyPrimitiveType ASSERT(count >= 0); @@ -355,7 +361,7 @@ index 0bb7489..b4b26a8 100644 { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create a 32-bit looping index buffer for GL_LINE_LOOP, too many indices required."); } -@@ -1157,42 +1244,12 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind +@@ -1223,42 +1322,12 @@ gl::Error Renderer11::drawLineLoop(GLsizei count, GLenum type, const GLvoid *ind return error; } @@ -402,8 +408,8 @@ index 0bb7489..b4b26a8 100644 error = mLineLoopIB->unmapBuffer(); if (error.isError()) { -@@ -1227,10 +1284,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * - indices = static_cast(storage->getData()) + offset; +@@ -1300,10 +1369,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * + indices = bufferData + offset; } + const int indexType = isLevel9() ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT; @@ -416,7 +422,7 @@ index 0bb7489..b4b26a8 100644 if (error.isError()) { SafeDelete(mTriangleFanIB); -@@ -1243,13 +1302,14 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * +@@ -1316,13 +1387,14 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * const unsigned int numTris = count - 2; @@ -434,7 +440,7 @@ index 0bb7489..b4b26a8 100644 if (error.isError()) { return error; -@@ -1263,45 +1323,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * +@@ -1336,45 +1408,12 @@ gl::Error Renderer11::drawTriangleFan(GLsizei count, GLenum type, const GLvoid * return error; } @@ -485,7 +491,7 @@ index 0bb7489..b4b26a8 100644 error = mTriangleFanIB->unmapBuffer(); if (error.isError()) -@@ -1549,7 +1576,7 @@ gl::Error Renderer11::applyUniforms(const gl::ProgramBinary &programBinary) +@@ -1634,7 +1673,7 @@ gl::Error Renderer11::applyUniforms(const ProgramImpl &program, const std::vecto } // needed for the point sprite geometry shader @@ -494,19 +500,7 @@ index 0bb7489..b4b26a8 100644 { mDeviceContext->GSSetConstantBuffers(0, 1, &mDriverConstantBufferPS); mCurrentGeometryConstantBuffer = mDriverConstantBufferPS; -@@ -1711,6 +1738,11 @@ bool Renderer11::testDeviceResettable() - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, -+#if !defined(ANGLE_ENABLE_D3D9) -+ D3D_FEATURE_LEVEL_9_3, -+ D3D_FEATURE_LEVEL_9_2, -+ D3D_FEATURE_LEVEL_9_1, -+#endif - }; - - ID3D11Device* dummyDevice; -@@ -1862,7 +1894,10 @@ int Renderer11::getMajorShaderModel() const +@@ -1938,7 +1977,10 @@ int Renderer11::getMajorShaderModel() const { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MAJOR_VERSION; // 5 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MAJOR_VERSION; // 4 @@ -518,7 +512,7 @@ index 0bb7489..b4b26a8 100644 default: UNREACHABLE(); return 0; } } -@@ -1873,7 +1908,10 @@ int Renderer11::getMinorShaderModel() const +@@ -1949,7 +1991,10 @@ int Renderer11::getMinorShaderModel() const { case D3D_FEATURE_LEVEL_11_0: return D3D11_SHADER_MINOR_VERSION; // 0 case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SHADER_MINOR_VERSION; // 1 @@ -530,49 +524,81 @@ index 0bb7489..b4b26a8 100644 default: UNREACHABLE(); return 0; } } -@@ -2387,6 +2425,15 @@ ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const ch - case D3D_FEATURE_LEVEL_10_0: - profileVersion = "4_0"; +@@ -2455,6 +2500,7 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin + + unsigned int profileMajorVersion = 0; + unsigned int profileMinorVersion = 0; ++ const char *profileSuffix = NULL; + switch (mFeatureLevel) + { + case D3D_FEATURE_LEVEL_11_0: +@@ -2469,12 +2515,30 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::strin + profileMajorVersion = 4; + profileMinorVersion = 0; break; + case D3D_FEATURE_LEVEL_9_3: -+ profileVersion = "4_0_level_9_3"; ++ profileMajorVersion = 4; ++ profileMinorVersion = 0; ++ profileSuffix = "_level_9_3"; + break; + case D3D_FEATURE_LEVEL_9_2: -+ profileVersion = "4_0_level_9_2"; ++ profileMajorVersion = 4; ++ profileMinorVersion = 0; ++ profileSuffix = "_level_9_2"; + break; + case D3D_FEATURE_LEVEL_9_1: -+ profileVersion = "4_0_level_9_1"; ++ profileMajorVersion = 4; ++ profileMinorVersion = 0; ++ profileSuffix = "_level_9_1"; + break; ++ break; default: UNREACHABLE(); - return NULL; + return gl::Error(GL_INVALID_OPERATION); + } + + std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion); ++ if (profileSuffix) ++ profile += profileSuffix; + + UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL2; + diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -index b86f5e5..2a53fa1 100644 +index c789cae..d44bd2f 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h -@@ -184,6 +184,7 @@ class Renderer11 : public Renderer +@@ -188,6 +188,7 @@ class Renderer11 : public RendererD3D ID3D11Device *getDevice() { return mDevice; } ID3D11DeviceContext *getDeviceContext() { return mDeviceContext; }; - IDXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + DXGIFactory *getDxgiFactory() { return mDxgiFactory; }; + bool isLevel9() { return mFeatureLevel <= D3D_FEATURE_LEVEL_9_3; } Blit11 *getBlitter() { return mBlit; } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp -index 3f0cd5b..91e7147 100644 +index 4287918..74af27e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp -@@ -472,7 +472,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform +@@ -744,7 +744,7 @@ gl::Error TextureStorage11_2D::getResource(ID3D11Resource **outResource) D3D11_TEXTURE2D_DESC desc; - desc.Width = width; // Compressed texture size constraints? - desc.Height = height; -- desc.MipLevels = ((levels > 0) ? (mTopLevel + levels) : 0); -+ desc.MipLevels = desc.MipLevels = mRenderer->isLevel9() ? 1 : ((levels > 0) ? (mTopLevel + levels) : 0); + desc.Width = mTextureWidth; // Compressed texture size constraints? + desc.Height = mTextureHeight; +- desc.MipLevels = mMipLevels; ++ desc.MipLevels = mRenderer->isLevel9() ? 1 : mMipLevels; desc.ArraySize = 1; desc.Format = mTextureFormat; desc.SampleDesc.Count = 1; +@@ -863,7 +863,7 @@ gl::Error TextureStorage11_2D::createSRV(int baseLevel, int mipLevels, DXGI_FORM + srvDesc.Format = format; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = mTopLevel + baseLevel; +- srvDesc.Texture2D.MipLevels = mipLevels; ++ srvDesc.Texture2D.MipLevels = mRenderer->isLevel9() ? -1 : mipLevels; + + ID3D11Device *device = mRenderer->getDevice(); + HRESULT result = device->CreateShaderResourceView(texture, &srvDesc, outSRV); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp -index 1ea916d..c078287 100644 +index 1ea916d..90a879e 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/formatutils11.cpp @@ -557,7 +557,7 @@ D3D11LoadFunctionMap BuildD3D11LoadFunctionMap() @@ -589,15 +615,15 @@ index 1ea916d..c078287 100644 // From GL_EXT_texture_storage // | GL internal format | D3D11 texture format | D3D11 SRV format | D3D11 RTV format | D3D11 DSV format | - InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN ); -+ InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); ++ InsertD3D11FormatInfo(&map, GL_ALPHA8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_LUMINANCE8_EXT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_ALPHA32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); InsertD3D11FormatInfo(&map, GL_LUMINANCE32F_EXT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_UNKNOWN ); diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index b1867fb..06a22eb 100644 +index 9ffc32e..cbfe557 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -283,7 +283,7 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +@@ -284,7 +284,7 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) // From http://msdn.microsoft.com/en-us/library/windows/desktop/ff476876.aspx case D3D_FEATURE_LEVEL_9_3: case D3D_FEATURE_LEVEL_9_2: @@ -607,5 +633,5 @@ index b1867fb..06a22eb 100644 default: UNREACHABLE(); return false; } -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch b/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch index 35d525fb2d..afc9f256a1 100644 --- a/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch +++ b/src/angle/patches/0012-ANGLE-fix-semantic-index-lookup.patch @@ -1,6 +1,6 @@ -From 9e167b788cc9de1d963fd3fc2145848a6ccc0fa8 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Mon, 22 Sep 2014 23:13:16 +0300 +From bbfd3cfcf6e1195d86368b61ce39504ce6acda50 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Wed, 12 Nov 2014 17:09:23 +0200 Subject: [PATCH 12/16] ANGLE: fix semantic index lookup The sorted semantic index table was returning a direct mapping to the @@ -14,10 +14,10 @@ Change-Id: I75d05ed707f56c45210e3dcbc277f894e3dc5a48 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp -index 1085346..3f6d9e0 100644 +index 0619023..6d64b38 100644 --- a/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp +++ b/src/3rdparty/angle/src/libGLESv2/ProgramBinary.cpp -@@ -2788,7 +2788,7 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA +@@ -1216,7 +1216,7 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++) { int oldIndex = mAttributesByLayout[i]; @@ -27,10 +27,10 @@ index 1085346..3f6d9e0 100644 } } diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp -index b006c04..d835e4f 100644 +index e41f238..ff90a6a 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp -@@ -112,10 +112,10 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl +@@ -113,10 +113,10 @@ gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl // Record the type of the associated vertex shader vector in our key // This will prevent mismatched vertex shaders from using the same input layout GLint attributeSize; @@ -44,5 +44,5 @@ index b006c04..d835e4f 100644 ilKey.elements[ilKey.elementCount].desc.InputSlot = i; ilKey.elements[ilKey.elementCount].desc.AlignedByteOffset = 0; -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch b/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch index 00e32186f0..b43dcc368b 100644 --- a/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch +++ b/src/angle/patches/0013-ANGLE-Add-support-for-querying-platform-device.patch @@ -1,6 +1,6 @@ -From 3499339ab768017458d3b5295af3742a0f6015db Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Mon, 22 Sep 2014 23:15:26 +0300 +From 5ef9348de2624c21be1c9fddd265fec5a0851d25 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Thu, 13 Nov 2014 15:34:26 +0200 Subject: [PATCH 13/16] ANGLE: Add support for querying platform device The EGL_EXT_device_base extension allows for querying the platform @@ -16,14 +16,14 @@ the IDXGIDevice3::Trim() calls required by the Windows Store. Change-Id: Ibdf228d81d6604e56db9dd8597d7cd2983ebc428 --- - src/3rdparty/angle/src/libEGL/libEGL.cpp | 47 +++++++++++++++++++++++++------- - 1 file changed, 37 insertions(+), 10 deletions(-) + src/3rdparty/angle/src/libEGL/libEGL.cpp | 50 +++++++++++++++++++++++++------- + 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/3rdparty/angle/src/libEGL/libEGL.cpp b/src/3rdparty/angle/src/libEGL/libEGL.cpp -index 7ea11c5..c2e0fd6 100644 +index dc20d85..68399d6 100644 --- a/src/3rdparty/angle/src/libEGL/libEGL.cpp +++ b/src/3rdparty/angle/src/libEGL/libEGL.cpp -@@ -18,6 +18,9 @@ +@@ -17,6 +17,9 @@ #include "libGLESv2/Texture.h" #include "libGLESv2/main.h" #include "libGLESv2/renderer/SwapChain.h" @@ -33,7 +33,7 @@ index 7ea11c5..c2e0fd6 100644 #include "libEGL/main.h" #include "libEGL/Display.h" -@@ -484,24 +487,48 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf +@@ -582,25 +585,50 @@ EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surf egl::Display *display = static_cast(dpy); egl::Surface *eglSurface = (egl::Surface*)surface; @@ -44,7 +44,8 @@ index 7ea11c5..c2e0fd6 100644 - - if (surface == EGL_NO_SURFACE) - { -- return egl::error(EGL_BAD_SURFACE, EGL_FALSE); +- recordError(egl::Error(EGL_BAD_SURFACE)); +- return EGL_FALSE; - } - switch (attribute) @@ -58,7 +59,8 @@ index 7ea11c5..c2e0fd6 100644 + + if (surface == EGL_NO_SURFACE) + { -+ return egl::error(EGL_BAD_SURFACE, EGL_FALSE); ++ recordError(egl::Error(EGL_BAD_SURFACE)); ++ return EGL_FALSE; + } + rx::SwapChain *swapchain = eglSurface->getSwapChain(); @@ -82,7 +84,8 @@ index 7ea11c5..c2e0fd6 100644 + + if (renderer->getMajorShaderModel() < 4) + { -+ return egl::error(EGL_BAD_CONTEXT, EGL_FALSE); ++ recordError(egl::Error(EGL_BAD_CONTEXT)); ++ return EGL_FALSE; + } + + *value = static_cast(renderer)->getDevice(); @@ -90,8 +93,8 @@ index 7ea11c5..c2e0fd6 100644 + break; +#endif default: - return egl::error(EGL_BAD_ATTRIBUTE, EGL_FALSE); - } + recordError(egl::Error(EGL_BAD_ATTRIBUTE)); + return EGL_FALSE; -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch b/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch index b884f7b549..9ceb34d964 100644 --- a/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch +++ b/src/angle/patches/0014-Let-ANGLE-use-multithreaded-devices-if-necessary.patch @@ -1,6 +1,6 @@ -From a3046fef7f754f06937161e779ce0a651e77317b Mon Sep 17 00:00:00 2001 +From 5b3bc73210ed1847d9bd7a94f06cc0d5de8e0b89 Mon Sep 17 00:00:00 2001 From: Michael Bruning -Date: Mon, 22 Sep 2014 23:23:40 +0300 +Date: Thu, 13 Nov 2014 15:40:10 +0200 Subject: [PATCH 14/16] Let ANGLE use multithreaded devices if necessary. This is needed to prevent lock-ups in application that use ANGLE from @@ -11,13 +11,13 @@ communicate this from the QtWebEngine module. Change-Id: Ibd5a5c75eb68af567d420d9a35efb3490c93b27c --- - src/3rdparty/angle/src/common/platform.h | 1 + - .../angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 13 +++++++++++++ - .../angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 ++++ - 3 files changed, 18 insertions(+) + src/3rdparty/angle/src/common/platform.h | 1 + + .../angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 10 ++++++++++ + .../angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 ++++ + 3 files changed, 15 insertions(+) diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 387ba41..7d0d957 100644 +index 0065ec7..8b2190d 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h @@ -57,6 +57,7 @@ @@ -26,17 +26,16 @@ index 387ba41..7d0d957 100644 # include +# include # include + # include # include - # include diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index b4b26a8..bd07ee1 100644 +index f6ba930..46b9984 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -301,6 +301,19 @@ EGLint Renderer11::initialize() +@@ -258,6 +258,16 @@ EGLint Renderer11::initialize() } - #endif -+#if !defined(ANGLE_PLATFORM_WINRT) + #if !defined(ANGLE_ENABLE_WINDOWS_STORE) + static wchar_t *qt_d3dcreate_multihreaded_var = _wgetenv(L"QT_D3DCREATE_MULTITHREADED"); + if (qt_d3dcreate_multihreaded_var && wcsstr(qt_d3dcreate_multihreaded_var, L"1")) + { @@ -47,16 +46,14 @@ index b4b26a8..bd07ee1 100644 + ASSERT(SUCCEEDED(result)); + multithread->Release(); + } -+#endif -+ - initializeDevice(); - - return EGL_SUCCESS; + #if !ANGLE_SKIP_DXGI_1_2_CHECK + // In order to create a swap chain for an HWND owned by another process, DXGI 1.2 is required. + // The easiest way to check is to query for a IDXGIDevice2. diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index e8564bd..1d52705 100644 +index 82963ec..4c552b2 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -304,6 +304,10 @@ EGLint Renderer9::initialize() +@@ -299,6 +299,10 @@ EGLint Renderer9::initialize() D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters(); DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; @@ -68,5 +65,5 @@ index e8564bd..1d52705 100644 result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice); } -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch b/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch index 7d914766a0..f78474f11a 100644 --- a/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch +++ b/src/angle/patches/0015-ANGLE-Fix-angle-d3d11-on-MSVC2010.patch @@ -1,23 +1,28 @@ -From 373b3f67352e9a6f599c6a9dd9aee3b4836e0a3f Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Mon, 22 Sep 2014 23:41:48 +0300 +From d9a9219ea2181dd4c1939d05747a21b67f16a906 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Thu, 13 Nov 2014 16:33:53 +0200 Subject: [PATCH 15/16] ANGLE: Fix -angle-d3d11 on MSVC2010 Allow the D3D11 renderer to build with the June 2010 DirectX SDK. Change-Id: I2343acedab16845d6a0d4a53cf3145f583efc4a7 --- - src/3rdparty/angle/src/common/platform.h | 6 ++ - .../renderer/d3d/d3d11/renderer11_utils.cpp | 89 ++++++++++++++++++++++ - 2 files changed, 95 insertions(+) + src/3rdparty/angle/src/common/platform.h | 8 +- + src/3rdparty/angle/src/libGLESv2/Context.cpp | 8 +- + src/3rdparty/angle/src/libGLESv2/Data.h | 2 +- + src/3rdparty/angle/src/libGLESv2/State.cpp | 6 +- + .../src/libGLESv2/renderer/d3d/RendererD3D.cpp | 4 +- + .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 4 +- + .../renderer/d3d/d3d11/renderer11_utils.cpp | 137 +++++++++++++++++++++ + 7 files changed, 156 insertions(+), 13 deletions(-) diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 7d0d957..3c619f3 100644 +index 8b2190d..972eee2 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h -@@ -52,7 +52,9 @@ +@@ -52,17 +52,23 @@ - # if defined(ANGLE_ENABLE_D3D9) || defined(ANGLE_ENABLE_PERF) + # if defined(ANGLE_ENABLE_D3D9) # include +# if !defined(COMPILER_IMPLEMENTATION) # include @@ -25,11 +30,13 @@ index 7d0d957..3c619f3 100644 # endif # if defined(ANGLE_ENABLE_D3D11) -@@ -60,8 +62,12 @@ + # include # include # include +-# include # include -+# if _MSC_VER >= 1700 ++# if defined(_MSC_VER) && (_MSC_VER >= 1700) ++# include # include +# endif +# if !defined(COMPILER_IMPLEMENTATION) @@ -37,12 +44,118 @@ index 7d0d957..3c619f3 100644 +# endif # endif - # undef near + # if defined(ANGLE_ENABLE_WINDOWS_STORE) +diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp +index fe9b1a2..b87689c 100644 +--- a/src/3rdparty/angle/src/libGLESv2/Context.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp +@@ -168,9 +168,9 @@ Context::~Context() + } + mIncompleteTextures.clear(); + +- for (auto &zeroTexture : mZeroTextures) ++ for (TextureMap::iterator i = mZeroTextures.begin(); i != mZeroTextures.end(); i++) + { +- zeroTexture.second.set(NULL); ++ i->second.set(NULL); + } + mZeroTextures.clear(); + +@@ -354,7 +354,7 @@ void Context::deleteFenceSync(GLsync fenceSync) + + void Context::deleteVertexArray(GLuint vertexArray) + { +- auto vertexArrayObject = mVertexArrayMap.find(vertexArray); ++ VertexArrayMap::iterator vertexArrayObject = mVertexArrayMap.find(vertexArray); + + if (vertexArrayObject != mVertexArrayMap.end()) + { +@@ -460,7 +460,7 @@ FenceSync *Context::getFenceSync(GLsync handle) const + + VertexArray *Context::getVertexArray(GLuint handle) const + { +- auto vertexArray = mVertexArrayMap.find(handle); ++ VertexArrayMap::const_iterator vertexArray = mVertexArrayMap.find(handle); + + if (vertexArray == mVertexArrayMap.end()) + { +diff --git a/src/3rdparty/angle/src/libGLESv2/Data.h b/src/3rdparty/angle/src/libGLESv2/Data.h +index cff872a..9234403 100644 +--- a/src/3rdparty/angle/src/libGLESv2/Data.h ++++ b/src/3rdparty/angle/src/libGLESv2/Data.h +@@ -14,7 +14,7 @@ + namespace gl + { + +-struct Data final ++struct Data + { + public: + Data(GLint clientVersion, const State &state, const Caps &caps, +diff --git a/src/3rdparty/angle/src/libGLESv2/State.cpp b/src/3rdparty/angle/src/libGLESv2/State.cpp +index e7acda2..b5b62f5 100644 +--- a/src/3rdparty/angle/src/libGLESv2/State.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/State.cpp +@@ -665,13 +665,13 @@ void State::detachTexture(const TextureMap &zeroTextures, GLuint texture) + + void State::initializeZeroTextures(const TextureMap &zeroTextures) + { +- for (const auto &zeroTexture : zeroTextures) ++ for (TextureMap::const_iterator i = zeroTextures.begin(); i != zeroTextures.end(); i++) + { +- auto &samplerTextureArray = mSamplerTextures[zeroTexture.first]; ++ TextureBindingVector &samplerTextureArray = mSamplerTextures[i->first]; + + for (size_t textureUnit = 0; textureUnit < samplerTextureArray.size(); ++textureUnit) + { +- samplerTextureArray[textureUnit].set(zeroTexture.second.get()); ++ samplerTextureArray[textureUnit].set(i->second.get()); + } + } + } +diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp +index 6f58243..97da6da 100644 +--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/RendererD3D.cpp +@@ -27,9 +27,9 @@ RendererD3D::RendererD3D(egl::Display *display) + + RendererD3D::~RendererD3D() + { +- for (auto &incompleteTexture : mIncompleteTextures) ++ for (gl::TextureMap::iterator i = mIncompleteTextures.begin(); i != mIncompleteTextures.end(); ++i) + { +- incompleteTexture.second.set(NULL); ++ i->second.set(NULL); + } + mIncompleteTextures.clear(); + } +diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +index 46b9984..a28fd78 100644 +--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +@@ -873,7 +873,7 @@ bool Renderer11::applyPrimitiveType(GLenum mode, GLsizei count) + + void Renderer11::unsetSRVsWithResource(gl::SamplerType samplerType, const ID3D11Resource *resource) + { +- auto ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); ++ std::vector ¤tSRVs = (samplerType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + for (size_t resourceIndex = 0; resourceIndex < currentSRVs.size(); ++resourceIndex) + { +@@ -3398,7 +3398,7 @@ Workarounds Renderer11::generateWorkarounds() const + + void Renderer11::setShaderResource(gl::SamplerType shaderType, UINT resourceSlot, ID3D11ShaderResourceView *srv) + { +- auto ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); ++ std::vector ¤tSRVs = (shaderType == gl::SAMPLER_VERTEX ? mCurVertexSRVs : mCurPixelSRVs); + + ASSERT(static_cast(resourceSlot) < currentSRVs.size()); + diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index 06a22eb..345fd24 100644 +index cbfe557..5831c57 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -17,6 +17,37 @@ +@@ -18,6 +18,85 @@ #include @@ -76,300 +189,348 @@ index 06a22eb..345fd24 100644 +#ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION +# define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 +#endif ++#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION ++# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 ++#endif ++#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION ++# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 ++#endif ++#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION ++# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 ++#endif ++#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP ++# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 ++#endif ++#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP ++# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 ++#endif ++#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT ++# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 ++#endif ++#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT ++# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 ++#endif ++#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT ++# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 ++#endif ++#ifndef D3D11_SO_BUFFER_SLOT_COUNT ++# define D3D11_SO_BUFFER_SLOT_COUNT 4 ++#endif ++#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT ++# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 ++#endif ++#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT ++# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 ++#endif ++#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE ++# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 ++#endif ++#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE ++# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 ++#endif ++#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT ++# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 ++#endif ++#ifndef D3D11_PS_INPUT_REGISTER_COUNT ++# define D3D11_PS_INPUT_REGISTER_COUNT 32 ++#endif ++#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT ++# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 ++#endif + namespace rx { -@@ -275,7 +306,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) +@@ -276,7 +355,9 @@ static bool GetNPOTTextureSupport(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return true; -@@ -293,7 +326,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) +@@ -294,7 +375,9 @@ static float GetMaximumAnisotropy(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_MAX_MAXANISOTROPY; case D3D_FEATURE_LEVEL_10_1: -@@ -313,7 +348,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) +@@ -314,7 +397,9 @@ static bool GetOcclusionQuerySupport(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return true; -@@ -333,7 +370,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) +@@ -334,7 +419,9 @@ static bool GetEventQuerySupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: -@@ -351,7 +390,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) +@@ -352,7 +439,9 @@ static bool GetInstancingSupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: -@@ -374,7 +415,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) +@@ -375,7 +464,9 @@ static bool GetDerivativeInstructionSupport(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: -@@ -392,7 +435,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel +@@ -393,7 +484,9 @@ static size_t GetMaximumSimultaneousRenderTargets(D3D_FEATURE_LEVEL featureLevel switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; case D3D_FEATURE_LEVEL_10_1: -@@ -410,7 +455,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) +@@ -411,7 +504,9 @@ static size_t GetMaximum2DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; case D3D_FEATURE_LEVEL_10_1: -@@ -428,7 +475,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) +@@ -429,7 +524,9 @@ static size_t GetMaximumCubeMapTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURECUBE_DIMENSION; case D3D_FEATURE_LEVEL_10_1: -@@ -446,7 +495,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) +@@ -447,7 +544,9 @@ static size_t GetMaximum2DTextureArraySize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; case D3D_FEATURE_LEVEL_10_1: -@@ -464,7 +515,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) +@@ -465,7 +564,9 @@ static size_t GetMaximum3DTextureSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; case D3D_FEATURE_LEVEL_10_1: -@@ -482,7 +535,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) +@@ -483,7 +584,9 @@ static size_t GetMaximumViewportSize(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_VIEWPORT_BOUNDS_MAX; case D3D_FEATURE_LEVEL_10_1: -@@ -506,7 +561,9 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) +@@ -507,7 +610,9 @@ static size_t GetMaximumDrawIndexedIndexCount(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); -@@ -528,7 +585,9 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) +@@ -529,7 +634,9 @@ static size_t GetMaximumDrawVertexCount(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return std::numeric_limits::max(); -@@ -545,7 +604,9 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) +@@ -546,7 +653,9 @@ static size_t GetMaximumVertexInputSlots(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_STANDARD_VERTEX_ELEMENT_COUNT; case D3D_FEATURE_LEVEL_10_1: return D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT; -@@ -565,7 +626,9 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) +@@ -566,7 +675,9 @@ static size_t GetMaximumVertexUniformVectors(D3D_FEATURE_LEVEL featureLevel) // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; case D3D_FEATURE_LEVEL_10_1: -@@ -590,7 +653,9 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +@@ -591,7 +702,9 @@ static size_t GetMaximumVertexUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedVertexUniformBuffers(); case D3D_FEATURE_LEVEL_10_1: -@@ -617,7 +682,9 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) +@@ -618,7 +731,9 @@ static size_t GetMaximumVertexOutputVectors(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); case D3D_FEATURE_LEVEL_10_1: return D3D10_1_VS_OUTPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); -@@ -636,7 +703,9 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) +@@ -637,7 +752,9 @@ static size_t GetMaximumVertexTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; case D3D_FEATURE_LEVEL_10_1: -@@ -658,7 +727,9 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) +@@ -659,7 +776,9 @@ static size_t GetMaximumPixelUniformVectors(D3D_FEATURE_LEVEL featureLevel) // TODO(geofflang): Remove hard-coded limit once the gl-uniform-arrays test can pass switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return 1024; // D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT; case D3D_FEATURE_LEVEL_10_1: -@@ -683,7 +754,9 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) +@@ -684,7 +803,9 @@ static size_t GetMaximumPixelUniformBlocks(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - GetReservedPixelUniformBuffers(); case D3D_FEATURE_LEVEL_10_1: -@@ -702,7 +775,9 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) +@@ -703,7 +824,9 @@ static size_t GetMaximumPixelInputVectors(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_PS_INPUT_REGISTER_COUNT - GetReservedVertexOutputVectors(); case D3D_FEATURE_LEVEL_10_1: -@@ -721,7 +796,9 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) +@@ -722,7 +845,9 @@ static size_t GetMaximumPixelTextureUnits(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; case D3D_FEATURE_LEVEL_10_1: -@@ -740,7 +817,9 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +@@ -741,7 +866,9 @@ static int GetMinimumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE; case D3D_FEATURE_LEVEL_10_1: -@@ -759,7 +838,9 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) +@@ -760,7 +887,9 @@ static int GetMaximumTexelOffset(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; case D3D_FEATURE_LEVEL_10_1: case D3D_FEATURE_LEVEL_10_0: return D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE; -@@ -782,7 +863,9 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) +@@ -783,7 +912,9 @@ static size_t GetMaximumConstantBufferSize(D3D_FEATURE_LEVEL featureLevel) switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * bytesPerComponent; case D3D_FEATURE_LEVEL_10_1: -@@ -801,7 +884,9 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) +@@ -802,7 +933,9 @@ static size_t GetMaximumStreamOutputBuffers(D3D_FEATURE_LEVEL featureLevel) { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: return D3D11_SO_BUFFER_SLOT_COUNT; case D3D_FEATURE_LEVEL_10_1: return D3D10_1_SO_BUFFER_SLOT_COUNT; -@@ -819,7 +904,9 @@ static size_t GetMaximumStreamOutputInterleavedComponenets(D3D_FEATURE_LEVEL fea +@@ -820,7 +953,9 @@ static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL feat { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif case D3D_FEATURE_LEVEL_11_0: case D3D_FEATURE_LEVEL_10_1: -@@ -837,7 +924,9 @@ static size_t GetMaximumStreamOutputSeparateCompeonents(D3D_FEATURE_LEVEL featur +@@ -838,7 +973,9 @@ static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL feature { switch (featureLevel) { -+#if _MSC_VER >= 1700 ++#if !defined(_MSC_VER) || (_MSC_VER >= 1800) case D3D_FEATURE_LEVEL_11_1: +#endif - case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponenets(featureLevel) / + case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) / GetMaximumStreamOutputBuffers(featureLevel); -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch b/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch index 2ea528018d..e3df95d8bf 100644 --- a/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch +++ b/src/angle/patches/0016-ANGLE-Fix-compilation-with-MinGW-D3D11.patch @@ -1,35 +1,29 @@ -From 75c39e9020f062d155097f6b49aebbc12970b1e8 Mon Sep 17 00:00:00 2001 -From: Andrew Knight -Date: Tue, 23 Sep 2014 23:39:14 +0300 +From 43c8ceb17ccd6d5ae13a07c6d01b45eb40983917 Mon Sep 17 00:00:00 2001 +From: Andrew Knight +Date: Tue, 11 Nov 2014 14:36:43 +0200 Subject: [PATCH 16/16] ANGLE: Fix compilation with MinGW + D3D11 -Provide workarounds for things GCC doesn't like, and define a number -of macros not found in the MinGW headers. +Provide workarounds for things GCC doesn't like, and define a few +missing definitions not found in the MinGW headers. Change-Id: I254c208209c0071fae5efb6727f2b3cfd5542da6 --- - src/3rdparty/angle/src/common/platform.h | 11 +++++ - src/3rdparty/angle/src/libEGL/Display.cpp | 1 + - src/3rdparty/angle/src/libGLESv2/Context.cpp | 5 +- - src/3rdparty/angle/src/libGLESv2/angletypes.h | 1 + - .../angle/src/libGLESv2/renderer/copyimage.inl | 2 +- - .../src/libGLESv2/renderer/d3d/TextureD3D.cpp | 4 +- + src/3rdparty/angle/src/common/platform.h | 73 ++++++++++++++++++++++ + .../src/libGLESv2/renderer/d3d/HLSLCompiler.cpp | 6 ++ .../libGLESv2/renderer/d3d/d3d11/Renderer11.cpp | 2 +- - .../libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp | 2 +- - .../renderer/d3d/d3d11/renderer11_utils.cpp | 53 +++++++++++++++++++++- + .../renderer/d3d/d3d11/renderer11_utils.cpp | 2 +- .../src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp | 4 +- - src/3rdparty/angle/src/libGLESv2/validationES.cpp | 2 +- - 11 files changed, 76 insertions(+), 11 deletions(-) + 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h -index 3c619f3..b53394f 100644 +index 972eee2..0001e71 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h -@@ -68,6 +68,17 @@ - # if !defined(COMPILER_IMPLEMENTATION) - # include - # endif -+# if defined(__MINGW32__) +@@ -81,6 +81,79 @@ + # endif + # endif + ++# if defined(__MINGW32__) // Missing defines on MinGW +typedef enum D3D11_MAP_FLAG +{ + D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000L @@ -39,202 +33,121 @@ index 3c619f3..b53394f 100644 + UINT64 NumPrimitivesWritten; + UINT64 PrimitivesStorageNeeded; +} D3D11_QUERY_DATA_SO_STATISTICS; -+# endif - # endif - ++typedef HRESULT (WINAPI *PFN_D3D11_CREATE_DEVICE)( ++ IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL *, ++ UINT FeatureLevels, UINT, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **); ++#define D3D11_MESSAGE_CATEGORY UINT ++#define D3D11_MESSAGE_SEVERITY UINT ++#define D3D11_MESSAGE_ID UINT ++struct D3D11_MESSAGE; ++typedef struct D3D11_INFO_QUEUE_FILTER_DESC ++{ ++ UINT NumCategories; ++ D3D11_MESSAGE_CATEGORY *pCategoryList; ++ UINT NumSeverities; ++ D3D11_MESSAGE_SEVERITY *pSeverityList; ++ UINT NumIDs; ++ D3D11_MESSAGE_ID *pIDList; ++} D3D11_INFO_QUEUE_FILTER_DESC; ++typedef struct D3D11_INFO_QUEUE_FILTER ++{ ++ D3D11_INFO_QUEUE_FILTER_DESC AllowList; ++ D3D11_INFO_QUEUE_FILTER_DESC DenyList; ++} D3D11_INFO_QUEUE_FILTER; ++static const IID IID_ID3D11InfoQueue = { 0x6543dbb6, 0x1b48, 0x42f5, 0xab, 0x82, 0xe9, 0x7e, 0xc7, 0x43, 0x26, 0xf6 }; ++MIDL_INTERFACE("6543dbb6-1b48-42f5-ab82-e97ec74326f6") ID3D11InfoQueue : public IUnknown ++{ ++public: ++ virtual HRESULT __stdcall SetMessageCountLimit(UINT64) = 0; ++ virtual void __stdcall ClearStoredMessages() = 0; ++ virtual HRESULT __stdcall GetMessage(UINT64, D3D11_MESSAGE *, SIZE_T *) = 0; ++ virtual UINT64 __stdcall GetNumMessagesAllowedByStorageFilter() = 0; ++ virtual UINT64 __stdcall GetNumMessagesDeniedByStorageFilter() = 0; ++ virtual UINT64 __stdcall GetNumStoredMessages() = 0; ++ virtual UINT64 __stdcall GetNumStoredMessagesAllowedByRetrievalFilter() = 0; ++ virtual UINT64 __stdcall GetNumMessagesDiscardedByMessageCountLimit() = 0; ++ virtual UINT64 __stdcall GetMessageCountLimit() = 0; ++ virtual HRESULT __stdcall AddStorageFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual HRESULT __stdcall GetStorageFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; ++ virtual void __stdcall ClearStorageFilter() = 0; ++ virtual HRESULT __stdcall PushEmptyStorageFilter() = 0; ++ virtual HRESULT __stdcall PushCopyOfStorageFilter() = 0; ++ virtual HRESULT __stdcall PushStorageFilter(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual void __stdcall PopStorageFilter() = 0; ++ virtual UINT __stdcall GetStorageFilterStackSize() = 0; ++ virtual HRESULT __stdcall AddRetrievalFilterEntries(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual HRESULT __stdcall GetRetrievalFilter(D3D11_INFO_QUEUE_FILTER *, SIZE_T *) = 0; ++ virtual void __stdcall ClearRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushEmptyRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushCopyOfRetrievalFilter() = 0; ++ virtual HRESULT __stdcall PushRetrievalFilter(D3D11_INFO_QUEUE_FILTER *) = 0; ++ virtual void __stdcall PopRetrievalFilter() = 0; ++ virtual UINT __stdcall GetRetrievalFilterStackSize() = 0; ++ virtual HRESULT __stdcall AddMessage(D3D11_MESSAGE_CATEGORY, D3D11_MESSAGE_SEVERITY, D3D11_MESSAGE_ID, LPCSTR) = 0; ++ virtual HRESULT __stdcall AddApplicationMessage(D3D11_MESSAGE_SEVERITY, LPCSTR) = 0; ++ virtual HRESULT __stdcall SetBreakOnCategory(D3D11_MESSAGE_CATEGORY, BOOL) = 0; ++ virtual HRESULT __stdcall SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY, BOOL) = 0; ++ virtual HRESULT __stdcall SetBreakOnID(D3D11_MESSAGE_ID, BOOL) = 0; ++ virtual BOOL __stdcall GetBreakOnCategory(D3D11_MESSAGE_CATEGORY) = 0; ++ virtual BOOL __stdcall GetBreakOnSeverity(D3D11_MESSAGE_SEVERITY) = 0; ++ virtual BOOL __stdcall GetBreakOnID(D3D11_MESSAGE_ID) = 0; ++ virtual void __stdcall SetMuteDebugOutput(BOOL) = 0; ++ virtual BOOL __stdcall GetMuteDebugOutput() = 0; ++}; ++#endif // __MINGW32__ ++ # undef near -diff --git a/src/3rdparty/angle/src/libEGL/Display.cpp b/src/3rdparty/angle/src/libEGL/Display.cpp -index ba09631..5a50e4b 100644 ---- a/src/3rdparty/angle/src/libEGL/Display.cpp -+++ b/src/3rdparty/angle/src/libEGL/Display.cpp -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include + # undef far + #endif +diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +index 9d003b4..776d92b 100644 +--- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp +@@ -14,6 +14,12 @@ + #ifndef QT_D3DCOMPILER_DLL + #define QT_D3DCOMPILER_DLL D3DCOMPILER_DLL + #endif ++#ifndef D3DCOMPILE_RESERVED16 ++#define D3DCOMPILE_RESERVED16 (1 << 16) ++#endif ++#ifndef D3DCOMPILE_RESERVED17 ++#define D3DCOMPILE_RESERVED17 (1 << 17) ++#endif - #include "common/debug.h" - #include "common/mathutil.h" -diff --git a/src/3rdparty/angle/src/libGLESv2/Context.cpp b/src/3rdparty/angle/src/libGLESv2/Context.cpp -index 04c7616..5342de1 100644 ---- a/src/3rdparty/angle/src/libGLESv2/Context.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/Context.cpp -@@ -33,6 +33,7 @@ - #include "libEGL/Surface.h" - - #include -+#include - - namespace gl - { -@@ -354,7 +355,7 @@ void Context::deleteFenceSync(GLsync fenceSync) - // wait commands finish. However, since the name becomes invalid, we cannot query the fence, - // and since our API is currently designed for being called from a single thread, we can delete - // the fence immediately. -- mResourceManager->deleteFenceSync(reinterpret_cast(fenceSync)); -+ mResourceManager->deleteFenceSync(uintptr_t(fenceSync)); - } - - void Context::deleteVertexArray(GLuint vertexArray) -@@ -460,7 +461,7 @@ Renderbuffer *Context::getRenderbuffer(GLuint handle) - - FenceSync *Context::getFenceSync(GLsync handle) const - { -- return mResourceManager->getFenceSync(reinterpret_cast(handle)); -+ return mResourceManager->getFenceSync(uintptr_t(handle)); - } - - VertexArray *Context::getVertexArray(GLuint handle) const -diff --git a/src/3rdparty/angle/src/libGLESv2/angletypes.h b/src/3rdparty/angle/src/libGLESv2/angletypes.h -index 922053e..642a6ec 100644 ---- a/src/3rdparty/angle/src/libGLESv2/angletypes.h -+++ b/src/3rdparty/angle/src/libGLESv2/angletypes.h -@@ -11,6 +11,7 @@ - - #include "libGLESv2/constants.h" - #include "common/RefCountObject.h" -+#include - - namespace gl - { -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl -index ea6970c..0498cf7 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/copyimage.inl -@@ -24,7 +24,7 @@ inline void WriteColor(const uint8_t *source, uint8_t *dest) - template - inline void CopyPixel(const uint8_t *source, uint8_t *dest) - { -- colorType temp; -+ colorDataType temp; - ReadColor(source, &temp); - WriteColor(&temp, dest); - } -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp -index 2650913..96c8497 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp -@@ -129,7 +129,7 @@ bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei w - if (unpack.pixelBuffer.id() != 0) - { - gl::Buffer *pixelBuffer = unpack.pixelBuffer.get(); -- unsigned int offset = reinterpret_cast(pixels); -+ ptrdiff_t offset = reinterpret_cast(pixels); - // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data. - // This functionality should be moved into renderer and the getData method of BufferImpl removed. - const void *bufferData = pixelBuffer->getImplementation()->getData(); -@@ -186,7 +186,7 @@ bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void - // to create a render target. - ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat)); - -- unsigned int offset = reinterpret_cast(pixels); -+ ptrdiff_t offset = reinterpret_cast(pixels); - - return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea); - } + // Definitions local to the translation unit + namespace diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -index bd07ee1..b29b2ef 100644 +index a28fd78..e6d7f30 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp -@@ -281,7 +281,7 @@ EGLint Renderer11::initialize() - } - +@@ -333,7 +333,7 @@ EGLint Renderer11::initialize() // Disable some spurious D3D11 debug warnings to prevent them from flooding the output log --#if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) -+#if !defined(__MINGW32__) && defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) + #if defined(ANGLE_SUPPRESS_D3D11_HAZARD_WARNINGS) && defined(_DEBUG) ID3D11InfoQueue *infoQueue; - result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); +- result = mDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&infoQueue); ++ result = mDevice->QueryInterface(IID_ID3D11InfoQueue, (void **)&infoQueue); -diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -index 787c511..4b29be0 100644 ---- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/SwapChain11.cpp -@@ -537,7 +537,7 @@ void SwapChain11::initPassThroughResources() - samplerDesc.BorderColor[2] = 0.0f; - samplerDesc.BorderColor[3] = 0.0f; - samplerDesc.MinLOD = 0; -- samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; -+ samplerDesc.MaxLOD = FLT_MAX; - - result = device->CreateSamplerState(&samplerDesc, &mPassThroughSampler); - ASSERT(SUCCEEDED(result)); + if (SUCCEEDED(result)) + { diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -index 345fd24..2af97e7 100644 +index 5831c57..121aa3b 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp -@@ -47,6 +47,57 @@ - #ifndef D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION - # define D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION 4096 - #endif -+#ifndef D3D11_REQ_TEXTURECUBE_DIMENSION -+# define D3D11_REQ_TEXTURECUBE_DIMENSION 16384 -+#endif -+#ifndef D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION -+# define D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION 2048 -+#endif -+#ifndef D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION -+# define D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION 2048 -+#endif -+#ifndef D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP -+# define D3D11_REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP 32 -+#endif -+#ifndef D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP -+# define D3D11_REQ_DRAW_VERTEX_COUNT_2_TO_EXP 32 -+#endif -+#ifndef D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT -+# define D3D10_1_STANDARD_VERTEX_ELEMENT_COUNT 32 -+#endif -+#ifndef D3D11_STANDARD_VERTEX_ELEMENT_COUNT -+# define D3D11_STANDARD_VERTEX_ELEMENT_COUNT 32 -+#endif -+#ifndef D3D10_1_SO_BUFFER_SLOT_COUNT -+# define D3D10_1_SO_BUFFER_SLOT_COUNT 4 -+#endif -+#ifndef D3D11_SO_BUFFER_SLOT_COUNT -+# define D3D11_SO_BUFFER_SLOT_COUNT 4 -+#endif -+#ifndef D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT -+# define D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT 14 -+#endif -+#ifndef D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT -+# define D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT 16 -+#endif -+#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -+# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE -8 -+#endif -+#ifndef D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE -+# define D3D11_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE 7 -+#endif -+#ifndef D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT -+# define D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT 4096 -+#endif -+#ifndef D3D11_PS_INPUT_REGISTER_COUNT -+# define D3D11_PS_INPUT_REGISTER_COUNT 32 -+#endif -+#ifndef D3D10_1_VS_OUTPUT_REGISTER_COUNT -+# define D3D10_1_VS_OUTPUT_REGISTER_COUNT 32 -+#endif -+#ifndef D3D11_VS_OUTPUT_REGISTER_COUNT -+# define D3D11_VS_OUTPUT_REGISTER_COUNT 32 -+#endif - - namespace rx - { -@@ -1147,7 +1198,7 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo +@@ -1196,7 +1196,7 @@ void SetPositionLayerTexCoord3DVertex(PositionLayerTexCoord3DVertex* vertex, flo HRESULT SetDebugName(ID3D11DeviceChild *resource, const char *name) { -#if defined(_DEBUG) -+#if !defined(__MINGW32__) && defined(_DEBUG) ++#if defined(_DEBUG) && !defined(__MINGW32__) return resource->SetPrivateData(WKPDID_D3DDebugObjectName, strlen(name), name); #else return S_OK; diff --git a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -index 1d52705..d63f9b8 100644 +index 4c552b2..601cd24 100644 --- a/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp +++ b/src/3rdparty/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp -@@ -205,7 +205,7 @@ EGLint Renderer9::initialize() - if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) +@@ -200,7 +200,7 @@ EGLint Renderer9::initialize() + if (ANGLE_D3D9EX == ANGLE_ENABLED && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex))) { ASSERT(mD3d9Ex); - mD3d9Ex->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast(&mD3d9)); @@ -242,7 +155,7 @@ index 1d52705..d63f9b8 100644 ASSERT(mD3d9); } else -@@ -329,7 +329,7 @@ EGLint Renderer9::initialize() +@@ -324,7 +324,7 @@ EGLint Renderer9::initialize() if (mD3d9Ex) { @@ -251,19 +164,6 @@ index 1d52705..d63f9b8 100644 ASSERT(SUCCEEDED(result)); } -diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.cpp b/src/3rdparty/angle/src/libGLESv2/validationES.cpp -index 1b6180d..f79bc97 100644 ---- a/src/3rdparty/angle/src/libGLESv2/validationES.cpp -+++ b/src/3rdparty/angle/src/libGLESv2/validationES.cpp -@@ -1667,7 +1667,7 @@ bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum t - // TODO: also disable index checking on back-ends that are robust to out-of-range accesses. - if (elementArrayBuffer) - { -- unsigned int offset = reinterpret_cast(indices); -+ GLint64 offset = reinterpret_cast(indices); - if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL)) - { - const void *dataPointer = elementArrayBuffer->getImplementation()->getData(); -- -1.9.0.msysgit.0 +1.9.4.msysgit.1 diff --git a/src/angle/src/libEGL/libEGL.pro b/src/angle/src/libEGL/libEGL.pro index 48ce7055fd..a16249309f 100644 --- a/src/angle/src/libEGL/libEGL.pro +++ b/src/angle/src/libEGL/libEGL.pro @@ -6,20 +6,40 @@ winrt: LIBS_PRIVATE += -ld3d11 LIBS_PRIVATE += -ldxguid -L$$QT_BUILD_TREE/lib -l$$qtLibraryTarget(libGLESv2) HEADERS += \ + $$ANGLE_DIR/src/common/NativeWindow.h \ + $$ANGLE_DIR/src/libEGL/AttributeMap.h \ $$ANGLE_DIR/src/libEGL/Config.h \ $$ANGLE_DIR/src/libEGL/Display.h \ + $$ANGLE_DIR/src/libEGL/Error.h \ $$ANGLE_DIR/src/libEGL/main.h \ $$ANGLE_DIR/src/libEGL/resource.h \ $$ANGLE_DIR/src/libEGL/ShaderCache.h \ $$ANGLE_DIR/src/libEGL/Surface.h SOURCES += \ + $$ANGLE_DIR/src/libEGL/AttributeMap.cpp \ $$ANGLE_DIR/src/libEGL/Config.cpp \ $$ANGLE_DIR/src/libEGL/Display.cpp \ + $$ANGLE_DIR/src/libEGL/Error.cpp \ $$ANGLE_DIR/src/libEGL/libEGL.cpp \ $$ANGLE_DIR/src/libEGL/main.cpp \ $$ANGLE_DIR/src/libEGL/Surface.cpp +!winrt { + SOURCES += \ + $$ANGLE_DIR/src/common/win32/NativeWindow.cpp +} else { + HEADERS += \ + $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.h \ + $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.h \ + $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.h + + SOURCES += \ + $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.cpp \ + $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.cpp \ + $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.cpp +} + !static { DEF_FILE = $$ANGLE_DIR/src/libEGL/$${TARGET}.def mingw:equals(QT_ARCH, i386): DEF_FILE = $$ANGLE_DIR/src/libEGL/$${TARGET}_mingw32.def diff --git a/src/angle/src/libGLESv2/libGLESv2.pro b/src/angle/src/libGLESv2/libGLESv2.pro index c0f7982e6c..705768d17d 100644 --- a/src/angle/src/libGLESv2/libGLESv2.pro +++ b/src/angle/src/libGLESv2/libGLESv2.pro @@ -24,11 +24,13 @@ HEADERS += \ $$ANGLE_DIR/src/common/blocklayout.h \ $$ANGLE_DIR/src/common/shadervars.h \ $$ANGLE_DIR/src/common/utilities.h \ + $$ANGLE_DIR/src/common/NativeWindow.h \ $$ANGLE_DIR/src/libGLESv2/angletypes.h \ $$ANGLE_DIR/src/libGLESv2/BinaryStream.h \ $$ANGLE_DIR/src/libGLESv2/Buffer.h \ $$ANGLE_DIR/src/libGLESv2/Caps.h \ $$ANGLE_DIR/src/libGLESv2/Context.h \ + $$ANGLE_DIR/src/libGLESv2/Data.h \ $$ANGLE_DIR/src/libGLESv2/Error.h \ $$ANGLE_DIR/src/libGLESv2/Fence.h \ $$ANGLE_DIR/src/libGLESv2/formatutils.h \ @@ -53,6 +55,8 @@ HEADERS += \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexDataManager.h \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/MemoryBuffer.h \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ProgramD3D.h \ + $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RenderbufferD3D.h \ + $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RendererD3D.h \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ShaderD3D.h \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureD3D.h \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureStorage.h \ @@ -69,6 +73,7 @@ HEADERS += \ $$ANGLE_DIR/src/libGLESv2/renderer/loadimage.h \ $$ANGLE_DIR/src/libGLESv2/renderer/ProgramImpl.h \ $$ANGLE_DIR/src/libGLESv2/renderer/QueryImpl.h \ + $$ANGLE_DIR/src/libGLESv2/renderer/RenderbufferImpl.h \ $$ANGLE_DIR/src/libGLESv2/renderer/Renderer.h \ $$ANGLE_DIR/src/libGLESv2/renderer/RenderTarget.h \ $$ANGLE_DIR/src/libGLESv2/renderer/ShaderExecutable.h \ @@ -77,6 +82,7 @@ HEADERS += \ $$ANGLE_DIR/src/libGLESv2/renderer/TextureImpl.h \ $$ANGLE_DIR/src/libGLESv2/renderer/TextureFeedbackImpl.h \ $$ANGLE_DIR/src/libGLESv2/renderer/VertexDeclarationCache.h \ + $$ANGLE_DIR/src/libGLESv2/renderer/Workarounds.h \ $$ANGLE_DIR/src/libGLESv2/resource.h \ $$ANGLE_DIR/src/libGLESv2/ResourceManager.h \ $$ANGLE_DIR/src/libGLESv2/Sampler.h \ @@ -102,6 +108,7 @@ SOURCES += \ $$ANGLE_DIR/src/libGLESv2/Buffer.cpp \ $$ANGLE_DIR/src/libGLESv2/Caps.cpp \ $$ANGLE_DIR/src/libGLESv2/Context.cpp \ + $$ANGLE_DIR/src/libGLESv2/Data.cpp \ $$ANGLE_DIR/src/libGLESv2/Error.cpp \ $$ANGLE_DIR/src/libGLESv2/Fence.cpp \ $$ANGLE_DIR/src/libGLESv2/Float16ToFloat32.cpp \ @@ -131,10 +138,12 @@ SOURCES += \ $$ANGLE_DIR/src/libGLESv2/VertexAttribute.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/copyimage.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/loadimage.cpp \ - $$ANGLE_DIR/src/libGLESv2/renderer/loadimageSSE2.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/Image.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/IndexRangeCache.cpp \ + $$ANGLE_DIR/src/libGLESv2/renderer/ProgramImpl.cpp \ + $$ANGLE_DIR/src/libGLESv2/renderer/RenderbufferImpl.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/Renderer.cpp \ + $$ANGLE_DIR/src/libGLESv2/renderer/RenderTarget.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/BufferD3D.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/DynamicHLSL.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp \ @@ -143,6 +152,8 @@ SOURCES += \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/IndexDataManager.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/MemoryBuffer.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ProgramD3D.cpp \ + $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RenderbufferD3D.cpp \ + $$ANGLE_DIR/src/libGLESv2/renderer/d3d/RendererD3D.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/ShaderD3D.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureD3D.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/TextureStorage.cpp \ @@ -192,6 +203,8 @@ angle_d3d11 { $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d11/VertexBuffer11.cpp } +SSE2_SOURCES += $$ANGLE_DIR/src/libGLESv2/renderer/loadimageSSE2.cpp + !winrt { HEADERS += \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Blit9.h \ @@ -211,6 +224,7 @@ angle_d3d11 { $$ANGLE_DIR/src/third_party/systeminfo/SystemInfo.h SOURCES += \ + $$ANGLE_DIR/src/common/win32/NativeWindow.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Buffer9.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/Fence9.cpp \ @@ -227,6 +241,16 @@ angle_d3d11 { $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/VertexBuffer9.cpp \ $$ANGLE_DIR/src/libGLESv2/renderer/d3d/d3d9/VertexDeclarationCache.cpp \ $$ANGLE_DIR/src/third_party/systeminfo/SystemInfo.cpp +} else { + HEADERS += \ + $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.h \ + $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.h \ + $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.h + + SOURCES += \ + $$ANGLE_DIR/src/common/winrt/CoreWindowNativeWindow.cpp \ + $$ANGLE_DIR/src/common/winrt/InspectableNativeWindow.cpp \ + $$ANGLE_DIR/src/common/winrt/SwapChainPanelNativeWindow.cpp } !static { From 4decaa566c1c7bcb29ed83cc8fed853c351f30dc Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 14 Nov 2014 16:16:13 +0200 Subject: [PATCH 242/323] Android: Extract default style Task-number: QTBUG-40621 Change-Id: I4569c87c79769752373a9e6e12cb64c89dfc8f94 Reviewed-by: J-P Nurmi --- .../qtproject/qt5/android/ExtractStyle.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index c65797a1de..c7cd2a263b 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1792,6 +1792,23 @@ public class ExtractStyle { } } + private JSONObject extractDefaultPalette() + { + TypedArray array = m_theme.obtainStyledAttributes(new int[]{ + android.R.attr.textAppearance + }); + int pos = 0; + JSONObject json = extractTextAppearance(array.getResourceId(pos++, -1)); + try { + json.put("defaultBackgroundColor", defaultBackgroundColor); + json.put("defaultTextColorPrimary", defaultTextColor); + } catch (Exception e) { + e.printStackTrace(); + } + array.recycle(); + return json; + } + public ExtractStyle(Context context, String extractPath) { // Log.i(MinistroService.TAG, "Extract " + extractPath); @@ -1803,9 +1820,13 @@ public class ExtractStyle { TypedArray array = m_theme.obtainStyledAttributes(new int[]{ android.R.attr.colorBackground, android.R.attr.textColorPrimary, + android.R.attr.textColor }); defaultBackgroundColor = array.getColor(0, 0); - defaultTextColor = array.getColor(1, 0xFFFFFF); + int textColor = array.getColor(1, 0xFFFFFF); + if (textColor == 0xFFFFFF) + textColor = array.getColor(2, 0xFFFFFF); + defaultTextColor = textColor; array.recycle(); try @@ -1813,6 +1834,7 @@ public class ExtractStyle { SimpleJsonWriter jsonWriter = new SimpleJsonWriter(m_extractPath+"style.json"); jsonWriter.beginObject(); try { + jsonWriter.name("defaultStyle").value(extractDefaultPalette()); extractWindow(jsonWriter, "windowStyle"); jsonWriter.name("buttonStyle").value(extractTextAppearanceInformations("buttonStyle", "QPushButton", null, -1)); jsonWriter.name("spinnerStyle").value(extractTextAppearanceInformations("spinnerStyle", "QComboBox", null, -1)); From acd06b6ef6c65d1e6a53f551895194512901f595 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 14 Nov 2014 17:49:32 +0200 Subject: [PATCH 243/323] Set Android palette and fonts in QPA plugin. Task-number: QTBUG-40621 Change-Id: Ibe069d4f93ac317e4f1b9ef5fc6bc3edcfac8685 Reviewed-by: J-P Nurmi --- .../android/qandroidplatformintegration.cpp | 22 +- .../android/qandroidplatformintegration.h | 6 +- .../android/qandroidplatformtheme.cpp | 297 +++++++++++++++++- .../platforms/android/qandroidplatformtheme.h | 16 +- src/widgets/styles/qandroidstyle.cpp | 260 +-------------- src/widgets/styles/qandroidstyle_p.h | 3 - 6 files changed, 335 insertions(+), 269 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 8a3a958d3b..07bdf95bf4 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -78,10 +78,24 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA return QtAndroid::javaVM(); if (resource == "QtActivity") return QtAndroid::activity(); - if (resource == "AndroidStylePalettes") - return &m_palettes; - if (resource == "AndroidStyleFonts") - return &m_fonts; + if (resource == "AndroidStyleData") { + if (m_androidStyle) + return &m_androidStyle->m_styleData; + else + return Q_NULLPTR; + } + if (resource == "AndroidStandardPalette") { + if (m_androidStyle) + return &m_androidStyle->m_standardPalette; + else + return Q_NULLPTR; + } + if (resource == "AndroidQWidgetFonts") { + if (m_androidStyle) + return &m_androidStyle->m_QWidgetsFonts; + else + return Q_NULLPTR; + } if (resource == "AndroidDeviceName") { static QString deviceName = QtAndroid::deviceName(); return &deviceName; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 13c98442e9..7b4ab08847 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -44,6 +44,8 @@ #include "qandroidplatformscreen.h" +#include + QT_BEGIN_NAMESPACE class QDesktopWidget; @@ -51,12 +53,12 @@ class QAndroidPlatformServices; class QAndroidSystemLocale; class QPlatformAccessibility; +struct AndroidStyle; class QAndroidPlatformNativeInterface: public QPlatformNativeInterface { public: void *nativeResourceForIntegration(const QByteArray &resource); - QHash m_palettes; - QHash m_fonts; + std::shared_ptr m_androidStyle; }; class QAndroidPlatformIntegration : public QPlatformIntegration diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 02974018aa..f9f2e4a944 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -37,17 +37,281 @@ #include "qandroidplatformmenu.h" #include "qandroidplatformmenuitem.h" #include "qandroidplatformdialoghelpers.h" -#include -#include + #include +#include +#include +#include +#include + #include #include QT_BEGIN_NAMESPACE +namespace { + const int textStyle_bold = 1; + const int textStyle_italic = 2; + + const int typeface_sans = 1; + const int typeface_serif = 2; + const int typeface_monospace = 3; +} + +static int fontType(const QString &androidControl) +{ + if (androidControl == QLatin1String("defaultStyle")) + return QPlatformTheme::SystemFont; + if (androidControl == QLatin1String("textViewStyle")) + return QPlatformTheme::LabelFont; + else if (androidControl == QLatin1String("buttonStyle")) + return QPlatformTheme::PushButtonFont; + else if (androidControl == QLatin1String("checkboxStyle")) + return QPlatformTheme::CheckBoxFont; + else if (androidControl == QLatin1String("radioButtonStyle")) + return QPlatformTheme::RadioButtonFont; + else if (androidControl == QLatin1String("simple_list_item_single_choice")) + return QPlatformTheme::ItemViewFont; + else if (androidControl == QLatin1String("simple_spinner_dropdown_item")) + return QPlatformTheme::ComboMenuItemFont; + else if (androidControl == QLatin1String("spinnerStyle")) + return QPlatformTheme::ComboLineEditFont; + else if (androidControl == QLatin1String("simple_list_item")) + return QPlatformTheme::ListViewFont; + return -1; +} + +static int paletteType(const QString &androidControl) +{ + if (androidControl == QLatin1String("defaultStyle")) + return QPlatformTheme::SystemPalette; + if (androidControl == QLatin1String("textViewStyle")) + return QPlatformTheme::LabelPalette; + else if (androidControl == QLatin1String("buttonStyle")) + return QPlatformTheme::ButtonPalette; + else if (androidControl == QLatin1String("checkboxStyle")) + return QPlatformTheme::CheckBoxPalette; + else if (androidControl == QLatin1String("radioButtonStyle")) + return QPlatformTheme::RadioButtonPalette; + else if (androidControl == QLatin1String("simple_list_item_single_choice")) + return QPlatformTheme::ItemViewPalette; + else if (androidControl == QLatin1String("editTextStyle")) + return QPlatformTheme::TextLineEditPalette; + else if (androidControl == QLatin1String("spinnerStyle")) + return QPlatformTheme::ComboBoxPalette; + return -1; +} + +static void setPaletteColor(const QVariantMap &object, + QPalette &palette, + QPalette::ColorRole role) +{ + // QPalette::Active -> ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + role, + QRgb(object.value(QLatin1String("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> ENABLED_STATE_SET + palette.setColor(QPalette::Inactive, + role, + QRgb(object.value(QLatin1String("ENABLED_STATE_SET")).toInt())); + + // QPalette::Disabled -> EMPTY_STATE_SET + palette.setColor(QPalette::Disabled, + role, + QRgb(object.value(QLatin1String("EMPTY_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, role, palette.color(QPalette::Active, role)); + + if (role == QPalette::WindowText) { + // QPalette::BrightText -> PRESSED + // QPalette::Active -> PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> PRESSED_ENABLED_STATE_SET + palette.setColor(QPalette::Inactive, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_ENABLED_STATE_SET")).toInt())); + + // QPalette::Disabled -> PRESSED_STATE_SET + palette.setColor(QPalette::Disabled, + QPalette::BrightText, + QRgb(object.value(QLatin1String("PRESSED_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, QPalette::BrightText, palette.color(QPalette::Active, QPalette::BrightText)); + + // QPalette::HighlightedText -> SELECTED + // QPalette::Active -> ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET + palette.setColor(QPalette::Active, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET")).toInt())); + + // QPalette::Inactive -> ENABLED_SELECTED_STATE_SET + palette.setColor(QPalette::Inactive, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("ENABLED_SELECTED_STATE_SET")).toInt())); + + // QPalette::Disabled -> SELECTED_STATE_SET + palette.setColor(QPalette::Disabled, + QPalette::HighlightedText, + QRgb(object.value(QLatin1String("SELECTED_STATE_SET")).toInt())); + + palette.setColor(QPalette::Current, + QPalette::HighlightedText, + palette.color(QPalette::Active, QPalette::HighlightedText)); + + // Same colors for Text + palette.setColor(QPalette::Active, QPalette::Text, palette.color(QPalette::Active, role)); + palette.setColor(QPalette::Inactive, QPalette::Text, palette.color(QPalette::Inactive, role)); + palette.setColor(QPalette::Disabled, QPalette::Text, palette.color(QPalette::Disabled, role)); + palette.setColor(QPalette::Current, QPalette::Text, palette.color(QPalette::Current, role)); + + // And for ButtonText + palette.setColor(QPalette::Active, QPalette::ButtonText, palette.color(QPalette::Active, role)); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, palette.color(QPalette::Inactive, role)); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, palette.color(QPalette::Disabled, role)); + palette.setColor(QPalette::Current, QPalette::ButtonText, palette.color(QPalette::Current, role)); + } +} + +static std::shared_ptr loadAndroidStyle(QPalette *defaultPalette) +{ + QString stylePath(QLatin1String(qgetenv("MINISTRO_ANDROID_STYLE_PATH"))); + const QLatin1Char slashChar('/'); + if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar)) + stylePath += slashChar; + + QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME")); + if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar)) + androidTheme += slashChar; + + if (stylePath.isEmpty()) { + stylePath = QLatin1String("/data/data/org.kde.necessitas.ministro/files/dl/style/") + + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) + slashChar; + } + Q_ASSERT(!stylePath.isEmpty()); + + if (!androidTheme.isEmpty() && QFileInfo(stylePath + androidTheme + QLatin1String("style.json")).exists()) + stylePath += androidTheme; + + QFile f(stylePath + QLatin1String("style.json")); + if (!f.open(QIODevice::ReadOnly)) + return std::shared_ptr(); + + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(f.readAll(), &error); + if (document.isNull()) { + qCritical() << error.errorString(); + return std::shared_ptr(); + } + + if (!document.isObject()) { + qCritical() << "Style.json does not contain a valid style."; + return std::shared_ptr(); + } + std::shared_ptr style(new AndroidStyle); + style->m_styleData = document.object(); + for (QJsonObject::const_iterator objectIterator = style->m_styleData.constBegin(); + objectIterator != style->m_styleData.constEnd(); + ++objectIterator) { + QString key = objectIterator.key(); + QJsonValue value = objectIterator.value(); + if (!value.isObject()) { + qWarning("Style.json structure is unrecognized."); + continue; + } + QJsonObject item = value.toObject(); + QJsonObject::const_iterator attributeIterator = item.find(QLatin1String("qtClass")); + QByteArray qtClassName; + if (attributeIterator != item.constEnd()) { + // The item has palette and font information for a specific Qt Class (e.g. QWidget, QPushButton, etc.) + qtClassName = attributeIterator.value().toString().toLatin1(); + } + const int ft = fontType(key); + if (ft > -1 || !qtClassName.isEmpty()) { + // Extract font information + QFont font; + + // Font size (in pixels) + attributeIterator = item.find(QLatin1String("TextAppearance_textSize")); + if (attributeIterator != item.constEnd()) + font.setPixelSize(int(attributeIterator.value().toDouble())); + + // Font style + attributeIterator = item.find(QLatin1String("TextAppearance_textStyle")); + if (attributeIterator != item.constEnd()) { + const int style = int(attributeIterator.value().toDouble()); + font.setBold(style & textStyle_bold); + font.setItalic(style & textStyle_italic); + } + + // Font typeface + attributeIterator = item.find(QLatin1String("TextAppearance_typeface")); + if (attributeIterator != item.constEnd()) { + QFont::StyleHint styleHint = QFont::AnyStyle; + switch (int(attributeIterator.value().toDouble())) { + case typeface_sans: + styleHint = QFont::SansSerif; + break; + case typeface_serif: + styleHint = QFont::Serif; + break; + case typeface_monospace: + styleHint = QFont::Monospace; + break; + } + font.setStyleHint(styleHint, QFont::PreferMatch); + } + if (!qtClassName.isEmpty()) + style->m_QWidgetsFonts.insert(qtClassName, font); + + if (ft > -1) { + style->m_fonts.insert(ft, font); + if (ft == QPlatformTheme::SystemFont) + QGuiApplication::setFont(font); + } + // Extract font information + } + + const int pt = paletteType(key); + if (pt > -1 || !qtClassName.isEmpty()) { + // Extract palette information + QPalette palette; + attributeIterator = item.find(QLatin1String("defaultTextColorPrimary")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::WindowText, QRgb(int(attributeIterator.value().toDouble()))); + + attributeIterator = item.find(QLatin1String("defaultBackgroundColor")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::Background, QRgb(int(attributeIterator.value().toDouble()))); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColor")); + if (attributeIterator != item.constEnd()) + setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::WindowText); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColorLink")); + if (attributeIterator != item.constEnd()) + setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::Link); + + attributeIterator = item.find(QLatin1String("TextAppearance_textColorHighlight")); + if (attributeIterator != item.constEnd()) + palette.setColor(QPalette::Highlight, QRgb(int(attributeIterator.value().toDouble()))); + + if (pt == QPlatformTheme::SystemPalette) + *defaultPalette = style->m_standardPalette = palette; + + if (pt > -1) + style->m_palettes.insert(pt, palette); + // Extract palette information + } + } + return style; +} + QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *androidPlatformNativeInterface) { - m_androidPlatformNativeInterface = androidPlatformNativeInterface; QColor background(229, 229, 229); QColor light = background.lighter(150); QColor mid(background.darker(130)); @@ -80,6 +344,9 @@ QAndroidPlatformTheme::QAndroidPlatformTheme(QAndroidPlatformNativeInterface *an m_defaultPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight); m_defaultPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight); m_defaultPalette.setBrush(QPalette::Disabled, QPalette::Highlight, highlight.lighter(150)); + m_androidStyleData = loadAndroidStyle(&m_defaultPalette); + QGuiApplication::setPalette(m_defaultPalette); + androidPlatformNativeInterface->m_androidStyle = m_androidStyleData; } QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const @@ -132,9 +399,11 @@ static inline int paletteType(QPlatformTheme::Palette type) const QPalette *QAndroidPlatformTheme::palette(Palette type) const { - QHash::const_iterator it = m_androidPlatformNativeInterface->m_palettes.find(paletteType(type)); - if (it != m_androidPlatformNativeInterface->m_palettes.end()) - return &(it.value()); + if (m_androidStyleData) { + auto it = m_androidStyleData->m_palettes.find(paletteType(type)); + if (it != m_androidStyleData->m_palettes.end()) + return &(it.value()); + } return &m_defaultPalette; } @@ -154,9 +423,11 @@ static inline int fontType(QPlatformTheme::Font type) const QFont *QAndroidPlatformTheme::font(Font type) const { - QHash::const_iterator it = m_androidPlatformNativeInterface->m_fonts.find(fontType(type)); - if (it != m_androidPlatformNativeInterface->m_fonts.end()) - return &(it.value()); + if (m_androidStyleData) { + auto it = m_androidStyleData->m_fonts.find(fontType(type)); + if (it != m_androidStyleData->m_fonts.end()) + return &(it.value()); + } // default in case the style has not set a font static QFont systemFont("Roboto", 14.0 * 100 / 72); // keep default size the same after changing from 100 dpi to 72 dpi @@ -165,18 +436,12 @@ const QFont *QAndroidPlatformTheme::font(Font type) const return 0; } -static const QLatin1String STYLES_PATH("/data/data/org.kde.necessitas.ministro/files/dl/style/"); -static const QLatin1String STYLE_FILE("/style.json"); - QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const { switch (hint) { case StyleNames: if (qgetenv("QT_USE_ANDROID_NATIVE_STYLE").toInt() - && (!qgetenv("MINISTRO_ANDROID_STYLE_PATH").isEmpty() - || QFileInfo(STYLES_PATH - + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) - + STYLE_FILE).exists())) { + && m_androidStyleData) { return QStringList("android"); } return QStringList("fusion"); diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h index 01611bf9d4..334e86ad7a 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.h +++ b/src/plugins/platforms/android/qandroidplatformtheme.h @@ -37,8 +37,22 @@ #include #include +#include + +#include + QT_BEGIN_NAMESPACE +struct AndroidStyle +{ + QJsonObject m_styleData; + QPalette m_standardPalette; + QHash m_palettes; + QHash m_fonts; + QHash m_QWidgetsFonts; + QHash m_QWidgetsPalettes; +}; + class QAndroidPlatformNativeInterface; class QAndroidPlatformTheme: public QPlatformTheme { @@ -57,7 +71,7 @@ public: private: - QAndroidPlatformNativeInterface * m_androidPlatformNativeInterface; + std::shared_ptr m_androidStyleData; QPalette m_defaultPalette; }; diff --git a/src/widgets/styles/qandroidstyle.cpp b/src/widgets/styles/qandroidstyle.cpp index 38c7497ffa..0bc0b4f087 100644 --- a/src/widgets/styles/qandroidstyle.cpp +++ b/src/widgets/styles/qandroidstyle.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -55,105 +54,33 @@ QT_BEGIN_NAMESPACE namespace { - const int textStyle_bold = 1; - const int textStyle_italic = 2; - - const int typeface_sans = 1; - const int typeface_serif = 2; - const int typeface_monospace = 3; - const quint32 NO_COLOR = 1; const quint32 TRANSPARENT_COLOR = 0; } -static int fontType(const QString &androidControl) -{ - if (androidControl == QLatin1String("textViewStyle")) - return QPlatformTheme::SystemFont; - else if (androidControl == QLatin1String("buttonStyle")) - return QPlatformTheme::PushButtonFont; - else if (androidControl == QLatin1String("checkboxStyle")) - return QPlatformTheme::CheckBoxFont; - else if (androidControl == QLatin1String("radioButtonStyle")) - return QPlatformTheme::RadioButtonFont; - else if (androidControl == QLatin1String("simple_list_item_single_choice")) - return QPlatformTheme::ItemViewFont; - else if (androidControl == QLatin1String("simple_spinner_dropdown_item")) - return QPlatformTheme::ComboMenuItemFont; - else if (androidControl == QLatin1String("spinnerStyle")) - return QPlatformTheme::ComboLineEditFont; - else if (androidControl == QLatin1String("simple_list_item")) - return QPlatformTheme::ListViewFont; - return -1; -} - -static int paletteType(const QString &androidControl) -{ - if (androidControl == QLatin1String("textViewStyle")) - return QPlatformTheme::SystemPalette; - else if (androidControl == QLatin1String("buttonStyle")) - return QPlatformTheme::ButtonPalette; - else if (androidControl == QLatin1String("checkboxStyle")) - return QPlatformTheme::CheckBoxPalette; - else if (androidControl == QLatin1String("radioButtonStyle")) - return QPlatformTheme::RadioButtonPalette; - else if (androidControl == QLatin1String("simple_list_item_single_choice")) - return QPlatformTheme::ItemViewPalette; - else if (androidControl == QLatin1String("editTextStyle")) - return QPlatformTheme::TextLineEditPalette; - else if (androidControl == QLatin1String("spinnerStyle")) - return QPlatformTheme::ComboBoxPalette; - return -1; -} - QAndroidStyle::QAndroidStyle() : QFusionStyle() { QPixmapCache::clear(); checkBoxControl = NULL; - QString stylePath(QLatin1String(qgetenv("MINISTRO_ANDROID_STYLE_PATH"))); - const QLatin1Char slashChar('/'); - if (!stylePath.isEmpty() && !stylePath.endsWith(slashChar)) - stylePath += slashChar; - - QString androidTheme = QLatin1String(qgetenv("QT_ANDROID_THEME")); - if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar)) - androidTheme += slashChar; - - if (stylePath.isEmpty()) { - stylePath = QLatin1String("/data/data/org.kde.necessitas.ministro/files/dl/style/") - + QLatin1String(qgetenv("QT_ANDROID_THEME_DISPLAY_DPI")) + slashChar; - } - Q_ASSERT(!stylePath.isEmpty()); - - if (!androidTheme.isEmpty() && QFileInfo(stylePath + androidTheme + QLatin1String("style.json")).exists()) - stylePath += androidTheme; - - QFile f(stylePath + QLatin1String("style.json")); - if (!f.open(QIODevice::ReadOnly)) - return; - - QJsonParseError error; - QJsonDocument document = QJsonDocument::fromJson(f.readAll(), &error); - if (document.isNull()) { - qCritical() << error.errorString(); - return; - } - - if (!document.isObject()) { - qCritical() << "Style.json does not contain a valid style."; - return; - } - QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); + QPalette *standardPalette = reinterpret_cast(nativeInterface->nativeResourceForIntegration("AndroidStandardPalette")); + if (standardPalette) + m_standardPalette = *standardPalette; - QHash *palettes = reinterpret_cast *>(nativeInterface->nativeResourceForIntegration("AndroidStylePalettes")); - QHash *fonts = reinterpret_cast *>(nativeInterface->nativeResourceForIntegration("AndroidStyleFonts")); - palettes->clear(); - fonts->clear(); - QJsonObject object = document.object(); - for (QJsonObject::const_iterator objectIterator = object.constBegin(); - objectIterator != object.constEnd(); + QHash *qwidgetsFonts = reinterpret_cast *>(nativeInterface->nativeResourceForIntegration("AndroidQWidgetFonts")); + if (qwidgetsFonts) { + for (auto it = qwidgetsFonts->constBegin(); it != qwidgetsFonts->constEnd(); ++it) + QApplication::setFont(it.value(), it.key()); + qwidgetsFonts->clear(); // free the memory + } + + QJsonObject *object = reinterpret_cast(nativeInterface->nativeResourceForIntegration("AndroidStyleData")); + if (!object) + return; + + for (QJsonObject::const_iterator objectIterator = object->constBegin(); + objectIterator != object->constEnd(); ++objectIterator) { QString key = objectIterator.key(); QJsonValue value = objectIterator.value(); @@ -163,85 +90,6 @@ QAndroidStyle::QAndroidStyle() } QJsonObject item = value.toObject(); - QJsonObject::const_iterator attributeIterator = item.find(QLatin1String("qtClass")); - QString qtClassName; - if (attributeIterator != item.constEnd()) { - // The item has palette and font information for a specific Qt Class (e.g. QWidget, QPushButton, etc.) - qtClassName = attributeIterator.value().toString(); - } - const int ft = fontType(key); - if (ft > -1 || !qtClassName.isEmpty()) { - // Extract font information - QFont font; - - // Font size (in pixels) - attributeIterator = item.find(QLatin1String("TextAppearance_textSize")); - if (attributeIterator != item.constEnd()) - font.setPixelSize(int(attributeIterator.value().toDouble())); - - // Font style - attributeIterator = item.find(QLatin1String("TextAppearance_textStyle")); - if (attributeIterator != item.constEnd()) { - const int style = int(attributeIterator.value().toDouble()); - font.setBold(style & textStyle_bold); - font.setItalic(style & textStyle_italic); - } - - // Font typeface - attributeIterator = item.find(QLatin1String("TextAppearance_typeface")); - if (attributeIterator != item.constEnd()) { - QFont::StyleHint styleHint = QFont::AnyStyle; - switch (int(attributeIterator.value().toDouble())) { - case typeface_sans: - styleHint = QFont::SansSerif; - break; - case typeface_serif: - styleHint = QFont::Serif; - break; - case typeface_monospace: - styleHint = QFont::Monospace; - break; - } - font.setStyleHint(styleHint, QFont::PreferMatch); - } - if (!qtClassName.isEmpty()) - QApplication::setFont(font, qtClassName.toUtf8()); - if (ft > -1) - fonts->insert(ft, font); - // Extract font information - } - - const int pt = paletteType(key); - if (pt > -1 || !qtClassName.isEmpty()) { - // Extract palette information - QPalette palette; - attributeIterator = item.find(QLatin1String("defaultTextColorPrimary")); - if (attributeIterator != item.constEnd()) - palette.setColor(QPalette::WindowText, QRgb(int(attributeIterator.value().toDouble()))); - - attributeIterator = item.find(QLatin1String("defaultBackgroundColor")); - if (attributeIterator != item.constEnd()) - palette.setColor(QPalette::Background, QRgb(int(attributeIterator.value().toDouble()))); - - attributeIterator = item.find(QLatin1String("TextAppearance_textColor")); - if (attributeIterator != item.constEnd()) - setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::WindowText); - - attributeIterator = item.find(QLatin1String("TextAppearance_textColorLink")); - if (attributeIterator != item.constEnd()) - setPaletteColor(attributeIterator.value().toObject().toVariantMap(), palette, QPalette::Link); - - attributeIterator = item.find(QLatin1String("TextAppearance_textColorHighlight")); - if (attributeIterator != item.constEnd()) - palette.setColor(QPalette::Highlight, QRgb(int(attributeIterator.value().toDouble()))); - - if (QLatin1String("QWidget") == qtClassName) - m_standardPalette = palette; - - if (pt > -1) - palettes->insert(pt, palette); - // Extract palette information - } QAndroidStyle::ItemType itemType = qtControl(key); if (QC_UnknownType == itemType) continue; @@ -277,6 +125,7 @@ QAndroidStyle::QAndroidStyle() break; } } + *object = QJsonObject(); // free memory } QAndroidStyle::~QAndroidStyle() @@ -284,81 +133,6 @@ QAndroidStyle::~QAndroidStyle() qDeleteAll(m_androidControlsHash); } - -void QAndroidStyle::setPaletteColor(const QVariantMap &object, - QPalette &palette, - QPalette::ColorRole role) -{ - // QPalette::Active -> ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET - palette.setColor(QPalette::Active, - role, - QRgb(object.value(QLatin1String("ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); - - // QPalette::Inactive -> ENABLED_STATE_SET - palette.setColor(QPalette::Inactive, - role, - QRgb(object.value(QLatin1String("ENABLED_STATE_SET")).toInt())); - - // QPalette::Disabled -> EMPTY_STATE_SET - palette.setColor(QPalette::Disabled, - role, - QRgb(object.value(QLatin1String("EMPTY_STATE_SET")).toInt())); - - palette.setColor(QPalette::Current, role, palette.color(QPalette::Active, role)); - - if (role == QPalette::WindowText) { - // QPalette::BrightText -> PRESSED - // QPalette::Active -> PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET - palette.setColor(QPalette::Active, - QPalette::BrightText, - QRgb(object.value(QLatin1String("PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET")).toInt())); - - // QPalette::Inactive -> PRESSED_ENABLED_STATE_SET - palette.setColor(QPalette::Inactive, - QPalette::BrightText, - QRgb(object.value(QLatin1String("PRESSED_ENABLED_STATE_SET")).toInt())); - - // QPalette::Disabled -> PRESSED_STATE_SET - palette.setColor(QPalette::Disabled, - QPalette::BrightText, - QRgb(object.value(QLatin1String("PRESSED_STATE_SET")).toInt())); - - palette.setColor(QPalette::Current, QPalette::BrightText, palette.color(QPalette::Active, QPalette::BrightText)); - - // QPalette::HighlightedText -> SELECTED - // QPalette::Active -> ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET - palette.setColor(QPalette::Active, - QPalette::HighlightedText, - QRgb(object.value(QLatin1String("ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET")).toInt())); - - // QPalette::Inactive -> ENABLED_SELECTED_STATE_SET - palette.setColor(QPalette::Inactive, - QPalette::HighlightedText, - QRgb(object.value(QLatin1String("ENABLED_SELECTED_STATE_SET")).toInt())); - - // QPalette::Disabled -> SELECTED_STATE_SET - palette.setColor(QPalette::Disabled, - QPalette::HighlightedText, - QRgb(object.value(QLatin1String("SELECTED_STATE_SET")).toInt())); - - palette.setColor(QPalette::Current, - QPalette::HighlightedText, - palette.color(QPalette::Active, QPalette::HighlightedText)); - - // Same colors for Text - palette.setColor(QPalette::Active, QPalette::Text, palette.color(QPalette::Active, role)); - palette.setColor(QPalette::Inactive, QPalette::Text, palette.color(QPalette::Inactive, role)); - palette.setColor(QPalette::Disabled, QPalette::Text, palette.color(QPalette::Disabled, role)); - palette.setColor(QPalette::Current, QPalette::Text, palette.color(QPalette::Current, role)); - - // And for ButtonText - palette.setColor(QPalette::Active, QPalette::ButtonText, palette.color(QPalette::Active, role)); - palette.setColor(QPalette::Inactive, QPalette::ButtonText, palette.color(QPalette::Inactive, role)); - palette.setColor(QPalette::Disabled, QPalette::ButtonText, palette.color(QPalette::Disabled, role)); - palette.setColor(QPalette::Current, QPalette::ButtonText, palette.color(QPalette::Current, role)); - } -} - QAndroidStyle::ItemType QAndroidStyle::qtControl(const QString &android) { if (android == QLatin1String("buttonStyle")) diff --git a/src/widgets/styles/qandroidstyle_p.h b/src/widgets/styles/qandroidstyle_p.h index 65fa4cd096..504d43fe96 100644 --- a/src/widgets/styles/qandroidstyle_p.h +++ b/src/widgets/styles/qandroidstyle_p.h @@ -376,9 +376,6 @@ private: static ItemType qtControl(QStyle::SubElement subElement); static ItemType qtControl(const QString &android); - static void setPaletteColor(const QVariantMap &object, - QPalette &palette, - QPalette::ColorRole role); private: typedef QHash AndroidControlsHash; AndroidControlsHash m_androidControlsHash; From c8751b3d84a5ba25effb88946fc56d989c5fa10a Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 14 Nov 2014 14:55:51 +0100 Subject: [PATCH 244/323] Doc: Corrected brief statement for overview page Task-number: QTBUG-42682 Change-Id: I28afbb8b09d5568f3fae29fdfc5a3d15376b72de Reviewed-by: Martin Smith --- src/corelib/doc/src/animation.qdoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc index 6910b18937..5839d42a39 100644 --- a/src/corelib/doc/src/animation.qdoc +++ b/src/corelib/doc/src/animation.qdoc @@ -27,6 +27,7 @@ /*! \group animation + \brief Provides an easy way for creating animated GUIs. \title Animation Framework This page lists classes belonging to \l{Qt Core}'s @@ -46,7 +47,7 @@ \keyword Animation The animation framework aims to provide an easy way for creating animated - and smooth GUI's. By animating Qt properties, the framework provides great + and smooth GUIs. By animating Qt properties, the framework provides great freedom for animating widgets and other \l{QObject}s. The framework can also be used with the Graphics View framework. Many of the concepts available in the animation framework are also available in \l{Qt Quick}, From 365212fedeef639787a2c183b1ae975b2a9cb9c3 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Fri, 14 Nov 2014 11:50:32 +0200 Subject: [PATCH 245/323] winrt: Blacklist certain devices from creating a depth/stencil buffer This passes the EGLConfig created in the platform screen to the underlying context, and certain GPUs are blacklisted to be prevented from creating a configuration which does not render properly with Qt Quick. Task-number: QTBUG-42260 Change-Id: I7e1cdc33c2f5662538723c6930fad5f13b151d6f Reviewed-by: Oliver Wolff --- .../platforms/winrt/qwinrteglcontext.cpp | 4 +- .../platforms/winrt/qwinrteglcontext.h | 2 +- .../platforms/winrt/qwinrtintegration.cpp | 2 +- src/plugins/platforms/winrt/qwinrtscreen.cpp | 43 ++++++++++++++++++- src/plugins/platforms/winrt/qwinrtscreen.h | 1 + 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 5daeee69c0..64aedb1b33 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -35,8 +35,8 @@ QT_BEGIN_NAMESPACE -QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface) - : QEGLPlatformContext(format, share, display), m_eglSurface(surface) +QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) + : QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface) { } diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index fb1199a79e..142e204fc8 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE class QWinRTEGLContext : public QEGLPlatformContext { public: - explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface); + explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index b8ca9fdc66..4fa90b4b68 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -110,7 +110,7 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QWinRTScreen *screen = static_cast(context->screen()->handle()); - return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface()); + return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig()); } QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 3933902ae3..681307ddcf 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -33,6 +33,11 @@ #include "qwinrtscreen.h" +#define EGL_EGLEXT_PROTOTYPES +#include +#include +#include + #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" @@ -452,6 +457,7 @@ public: EGLDisplay eglDisplay; EGLSurface eglSurface; + EGLConfig eglConfig; QHash applicationTokens; QHash windowTokens; @@ -575,7 +581,36 @@ QWinRTScreen::QWinRTScreen() if (!eglInitialize(d->eglDisplay, NULL, NULL)) qCritical("Failed to initialize EGL: 0x%x", eglGetError()); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, q_configFromGLFormat(d->eglDisplay, d->surfaceFormat), d->coreWindow.Get(), NULL); + // Check that the device properly supports depth/stencil rendering, and disable them if not + ComPtr d3dDevice; + const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); + if (ok && d3dDevice) { + ComPtr dxgiDevice; + hr = d3dDevice.As(&dxgiDevice); + if (SUCCEEDED(hr)) { + ComPtr dxgiAdapter; + hr = dxgiDevice->GetAdapter(&dxgiAdapter); + if (SUCCEEDED(hr)) { + ComPtr dxgiAdapter2; + hr = dxgiAdapter.As(&dxgiAdapter2); + if (SUCCEEDED(hr)) { + DXGI_ADAPTER_DESC2 desc; + hr = dxgiAdapter2->GetDesc2(&desc); + if (SUCCEEDED(hr)) { + // The following GPUs do not render properly with depth/stencil + if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225 + d->surfaceFormat.setDepthBufferSize(-1); + d->surfaceFormat.setStencilBufferSize(-1); + } + } + } + } + } + } + + d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); + d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); if (d->eglSurface == EGL_NO_SURFACE) qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); } @@ -706,6 +741,12 @@ EGLSurface QWinRTScreen::eglSurface() const return d->eglSurface; } +EGLConfig QWinRTScreen::eglConfig() const +{ + Q_D(const QWinRTScreen); + return d->eglConfig; +} + QWindow *QWinRTScreen::topWindow() const { Q_D(const QWinRTScreen); diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index e70a998216..c95a2073ed 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -109,6 +109,7 @@ public: ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; EGLDisplay eglDisplay() const; // To opengl context EGLSurface eglSurface() const; // To window + EGLConfig eglConfig() const; private: void handleExpose(); From f1aafb595bb5b9bd9b8d3299e5722bcc35aea889 Mon Sep 17 00:00:00 2001 From: "N.Sukegawa" Date: Sat, 8 Nov 2014 20:42:00 +0900 Subject: [PATCH 246/323] Make configure fail on invalid (-no)-feature options configure script has been silently accepting whatever flags that begin with "-feature-" even if the feature name does not exist at all. Since the script validates many other flags, this behavior can make users believe flags they supply is valid when it isn't. Besides, this option is currently not protected against typo in any way. This commit verifies those flags against content of "qtbase/src/corelib/global/qfeatures.txt" and fails if supplied flag is not a valid feature name. Change-Id: Ib19ec66dd5558fb5491e8e080ce07d4807d94c1f Reviewed-by: Oswald Buddenhagen --- configure | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 1bd7db88b3..418d5a4daf 100755 --- a/configure +++ b/configure @@ -1409,7 +1409,8 @@ while [ "$#" -gt 0 ]; do fi ;; feature-*) - FEATURE=`echo $VAR | sed 's,^[^-]*-\([^-]*\),\1,' | tr 'abcdefghijklmnopqrstuvwxyz-' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` + FEATURE=`echo $VAR | sed 's,^[^-]*-\([^-]*\),\1,' | tr 'abcdefghijklmnopqrstuvwxyz-' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` + if grep "^Feature: *${FEATURE} *\$" "$relpath"/src/corelib/global/qfeatures.txt >/dev/null 2>&1; then if [ "$VAL" = "no" ]; then QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_$FEATURE" elif [ "$VAL" = "yes" ] || [ "$VAL" = "unknown" ]; then @@ -1417,6 +1418,10 @@ while [ "$#" -gt 0 ]; do else UNKNOWN_OPT=yes fi + else + echo "ERROR: Unknown feature $FEATURE" + UNKNOWN_OPT=yes + fi ;; shared) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then From e7839239eb62da495f54f11a9f72be6bbc4a053e Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 13 Nov 2014 15:47:16 +0200 Subject: [PATCH 247/323] Android: Extract AnimatedStateListDrawable Task-number: QTBUG-42488 Change-Id: I6400c5ba54bdc9a0e1db71986432a6653da9e534 Reviewed-by: J-P Nurmi Reviewed-by: BogDan Vatra --- .../qtproject/qt5/android/ExtractStyle.java | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index c7cd2a263b..4dbc33057b 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -49,6 +49,7 @@ import java.io.OutputStreamWriter; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import org.json.JSONArray; import org.json.JSONException; @@ -97,6 +98,8 @@ public class ExtractStyle { Class styleableClass = getClass("android.R$styleable"); Class rippleDrawableClass = getClass("android.graphics.drawable.RippleDrawable"); + Class animatedStateListDrawableClass = getClass("android.graphics.drawable.AnimatedStateListDrawable"); + final int[] EMPTY_STATE_SET = {}; final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled}; final int[] FOCUSED_STATE_SET = {android.R.attr.state_focused}; @@ -631,10 +634,9 @@ public class ExtractStyle { JSONObject stateJson = new JSONObject(); final Drawable d = (Drawable) StateListDrawable.class.getMethod("getStateDrawable", Integer.TYPE).invoke(stateList, i); final int [] states = (int[]) StateListDrawable.class.getMethod("getStateSet", Integer.TYPE).invoke(stateList, i); - if (states == null) - continue; - stateJson.put("states", getStatesList(states)); - stateJson.put("drawable", getDrawable(d, filename+"__"+getStatesName(states), null)); + if (states != null) + stateJson.put("states", getStatesList(states)); + stateJson.put("drawable", getDrawable(d, filename+"__" + (states != null ? getStatesName(states) : ("state_pos_" + i)), null)); array.put(stateJson); } json.put("type", "stateslist"); @@ -810,6 +812,67 @@ public class ExtractStyle { return json; } + private HashMap getStateTransitions(Object sa) throws Exception + { + HashMap transitions = new HashMap(); + final int sz = getAccessibleField(sa.getClass(), "mSize").getInt(sa); + long[] keys = (long[]) getAccessibleField(sa.getClass(), "mKeys").get(sa); + long[] values = (long[]) getAccessibleField(sa.getClass(), "mValues").get(sa); + for (int i = 0; i < sz; i++) { + transitions.put(keys[i], values[i]); + } + return transitions; + } + + private HashMap getStateIds(Object sa) throws Exception + { + HashMap states = new HashMap(); + final int sz = getAccessibleField(sa.getClass(), "mSize").getInt(sa); + int[] keys = (int[]) getAccessibleField(sa.getClass(), "mKeys").get(sa); + int[] values = (int[]) getAccessibleField(sa.getClass(), "mValues").get(sa); + for (int i = 0; i < sz; i++) { + states.put(keys[i], values[i]); + } + return states; + } + + private int findStateIndex(int id, HashMap stateIds) + { + for (Map.Entry s : stateIds.entrySet()) { + if (id == s.getValue()) + return s.getKey(); + } + return -1; + } + + private JSONObject getAnimatedStateListDrawable(Object drawable, String filename) + { + JSONObject json = getStateListDrawable(drawable, filename); + try { + Object state = getAccessibleField(animatedStateListDrawableClass, "mState").get(drawable); + + HashMap stateIds = getStateIds(getAccessibleField(state.getClass(), "mStateIds").get(state)); + HashMap transitions = getStateTransitions(getAccessibleField(state.getClass(), "mTransitions").get(state)); + + for (Map.Entry t : transitions.entrySet()) { + final int toState = findStateIndex(t.getKey().intValue(), stateIds); + final int fromState = findStateIndex((int) (t.getKey() >> 32), stateIds); + + JSONObject transition = new JSONObject(); + transition.put("from", fromState); + transition.put("to", toState); + transition.put("reverse", (t.getValue() >> 32) != 0); + + JSONArray stateslist = json.getJSONArray("stateslist"); + JSONObject stateobj = stateslist.getJSONObject(t.getValue().intValue()); + stateobj.put("transition", transition); + } + } catch (Exception e) { + e.printStackTrace(); + } + return json; + } + public JSONObject getDrawable(Object drawable, String filename, Rect padding) { if (drawable == null) @@ -855,6 +918,10 @@ public class ExtractStyle { if (rippleDrawableClass != null && rippleDrawableClass.isInstance(drawable)) return getRippleDrawable(drawable, filename, padding); + + if (animatedStateListDrawableClass != null && animatedStateListDrawableClass.isInstance(drawable)) + return getAnimatedStateListDrawable(drawable, filename); + if (drawable instanceof ScaleDrawable) { return getDrawable(((ScaleDrawable)drawable).getDrawable(), filename, null); From 68862c7231d257c2c1b17ddcb60cc742098d5ed5 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 13 Nov 2014 12:01:44 +0100 Subject: [PATCH 248/323] rcc: Change two-pass feature from opt-out to opt-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the 'big-data' feature introduced and made mandatory with commit 5395180 opt-in trough CONFIG += resources_big. Since the feature has been introduced several setups have been found where the feature cannot be used, or not be used out-of-the-box. Using the traditional default behavior lowers the risk of further breakages. Change-Id: Ifd04204adadeec539e962d6a9a6955f63781bd36 Reviewed-by: Oswald Buddenhagen Reviewed-by: Fawzi Mohamed Reviewed-by: Tor Arne Vestbø Reviewed-by: Frederik Gladhorn --- mkspecs/features/resources.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/resources.prf b/mkspecs/features/resources.prf index 27db7d7d7a..8564731a22 100644 --- a/mkspecs/features/resources.prf +++ b/mkspecs/features/resources.prf @@ -11,7 +11,7 @@ rcc.name = RCC ${QMAKE_FILE_IN} rcc.depend_command = $$QMAKE_RCC_DEP -list $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} rcc.CONFIG += add_inputs_as_makefile_deps -resources_small|ltcg|macx-xcode|contains(TEMPLATE, "vc.*") { +!resources_big|ltcg|macx-xcode|contains(TEMPLATE, "vc.*") { rcc.output = $$RCC_DIR/$${first(QMAKE_MOD_RCC)}_${QMAKE_FILE_BASE}$${first(QMAKE_EXT_CPP)} rcc.commands = $$QMAKE_RCC $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} From 2f1d22c8b4033b7160dde08ba232d22a620f8cd7 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 7 Nov 2014 10:52:34 +0100 Subject: [PATCH 249/323] qdoc: Removed text formatting from requisites table Removed the teletype (code) formatting used in the requisite table: include, qmake (qtvariable) and import statement (for QML types). This makes the table look more uniform as it doesn't mix font styles anymore. Also, remove the closing tag that caused incorrect html to be generated. Change-Id: I180a90c22d4b0066aade8ce38d13343076285ff0 Reviewed-by: Martin Smith --- src/tools/qdoc/htmlgenerator.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index bd8d45ab53..0f5bf26e71 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -1898,12 +1898,9 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) //add the includes to the map if (!inner->includes().isEmpty()) { text.clear(); - text << formattingRightMap()[ATOM_FORMATTING_BOLD] - << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] - << highlightedCode(indent(codeIndent, + text << highlightedCode(indent(codeIndent, marker->markedUpIncludes(inner->includes())), - inner) - << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + inner); requisites.insert(headerText, text); } @@ -1938,9 +1935,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker) ModuleNode* moduleNode = qdb_->findModule(inner->moduleName()); if (moduleNode && !moduleNode->qtVariable().isEmpty()) { text.clear(); - text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE) - << "QT += " + moduleNode->qtVariable() - << Atom(Atom::FormattingRight, ATOM_FORMATTING_TELETYPE); + text << "QT += " + moduleNode->qtVariable(); requisites.insert(qtVariableText, text); } } @@ -2053,10 +2048,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker) else qmlModuleVersion = qcn->qmlModuleVersion(); text.clear(); - text << formattingRightMap()[ATOM_FORMATTING_BOLD] - << formattingLeftMap()[ATOM_FORMATTING_TELETYPE] - << "import " + qcn->qmlModuleName() + " " + qmlModuleVersion - << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; + text << "import " + qcn->qmlModuleName() + " " + qmlModuleVersion; requisites.insert(importText, text); //add the since and project into the map From 1ffe39dfd155c1318e249591c71e808437cc9696 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 28 Oct 2014 10:00:56 +0100 Subject: [PATCH 250/323] Make it possible to disable font embedding When font embedding is explicitly disabled, fall back to painter paths as we would if the font prohibits embedding. Note that this flag was never respected on any platform in any version of Qt, as far as I've been able to tell, because the handling of it in the X11 print engine was removed shortly after it was introduced in 2005. [ChangeLog][Printing] Disabling font embedding is now possible using the QPrinter::setFontEmbedding() function. Task-number: QTBUG-41943 Change-Id: Ice5e893f9893c5243310ae7892bec7497dd55c4a Reviewed-by: Konstantin Ritt Reviewed-by: Lars Knoll --- src/gui/painting/qpdf.cpp | 3 ++- .../platforms/cocoa/qprintengine_mac.mm | 16 +++++++++------ .../platforms/cocoa/qprintengine_mac_p.h | 3 ++- src/printsupport/kernel/qprintengine_win.cpp | 16 +++++++++------ src/printsupport/kernel/qprintengine_win_p.h | 4 +++- src/printsupport/kernel/qprinter.cpp | 4 ---- .../kernel/qprinter/tst_qprinter.cpp | 20 +++++-------------- 7 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 9082f98205..46d016de6b 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -2501,7 +2501,8 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti) QFontEngine::FaceId face_id = fe->faceId(); bool noEmbed = false; - if (face_id.filename.isEmpty() + if (!embedFonts + || face_id.filename.isEmpty() || fe->fsType & 0x200 /* bitmap embedding only */ || fe->fsType == 2 /* no embedding allowed */) { *currentPage << "Q\n"; diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index f684fef233..a58514614b 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -412,7 +412,10 @@ void QMacPrintEngine::drawTextItem(const QPointF &p, const QTextItem &ti) { Q_D(QMacPrintEngine); Q_ASSERT(d->state == QPrinter::Active); - d->paintEngine->drawTextItem(p, ti); + if (!d->embedFonts) + QPaintEngine::drawTextItem(p, ti); + else + d->paintEngine->drawTextItem(p, ti); } void QMacPrintEngine::drawTiledPixmap(const QRectF &dr, const QPixmap &pixmap, const QPointF &sr) @@ -457,8 +460,6 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va break; case PPK_CustomBase: break; - case PPK_FontEmbedding: - break; case PPK_PageOrder: // TODO Check if can be supported via Cups Options break; @@ -471,6 +472,9 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va break; // The following keys are properties and settings that are supported by the Mac PrintEngine + case PPK_FontEmbedding: + d->embedFonts = value.toBool(); + break; case PPK_Resolution: { // TODO It appears the old code didn't actually set the resolution??? Can we delete all this??? int bestResolution = 0; @@ -622,9 +626,6 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_CustomBase: // Special case, leave null break; - case PPK_FontEmbedding: - ret = false; - break; case PPK_PageOrder: // TODO Check if can be supported via Cups Options ret = QPrinter::FirstPageFirst; @@ -648,6 +649,9 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const break; // The following keys are properties and settings that are supported by the Mac PrintEngine + case PPK_FontEmbedding: + ret = d->embedFonts; + break; case PPK_CollateCopies: { Boolean status; PMGetCollate(d->settings(), &status); diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h index c7307688ae..c99069b7f7 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h +++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h @@ -124,10 +124,11 @@ public: QString m_creator; QPaintEngine *paintEngine; QHash valueCache; + uint embedFonts; QMacPrintEnginePrivate() : mode(QPrinter::ScreenResolution), state(QPrinter::Idle), m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))), - printInfo(0), paintEngine(0) {} + printInfo(0), paintEngine(0), embedFonts(true) {} ~QMacPrintEnginePrivate(); void initialize(); diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 7f5e83c61e..4e0a3e0795 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -269,7 +269,8 @@ void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem bool fallBack = state->pen().brush().style() != Qt::SolidPattern || qAlpha(brushColor) != 0xff || d->txop >= QTransform::TxProject - || ti.fontEngine->type() != QFontEngine::Win; + || ti.fontEngine->type() != QFontEngine::Win + || !d->embed_fonts; if (!fallBack) { const QVariantMap userData = ti.fontEngine->userData().toMap(); @@ -1001,8 +1002,6 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & // The following keys are settings that are unsupported by the Windows PrintEngine case PPK_CustomBase: break; - case PPK_FontEmbedding: - break; case PPK_PageOrder: break; case PPK_PrinterProgram: @@ -1011,6 +1010,10 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant & break; // The following keys are properties and settings that are supported by the Windows PrintEngine + case PPK_FontEmbedding: + d->embed_fonts = value.toBool(); + break; + case PPK_CollateCopies: { if (!d->devMode) @@ -1282,9 +1285,6 @@ QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const // The following keys are settings that are unsupported by the Windows PrintEngine // Return sensible default values to ensure consistent behavior across platforms - case PPK_FontEmbedding: - value = false; - break; case PPK_PageOrder: value = QPrinter::FirstPageFirst; break; @@ -1296,6 +1296,10 @@ QVariant QWin32PrintEngine::property(PrintEnginePropertyKey key) const break; // The following keys are properties and settings that are supported by the Windows PrintEngine + case PPK_FontEmbedding: + value = d->embed_fonts; + break; + case PPK_CollateCopies: value = d->devMode->dmCollate == DMCOLLATE_TRUE; break; diff --git a/src/printsupport/kernel/qprintengine_win_p.h b/src/printsupport/kernel/qprintengine_win_p.h index b84bde8a92..0a87795bb8 100644 --- a/src/printsupport/kernel/qprintengine_win_p.h +++ b/src/printsupport/kernel/qprintengine_win_p.h @@ -125,7 +125,8 @@ public: m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))), num_copies(1), printToFile(false), - reinit(false) + reinit(false), + embed_fonts(true) { } @@ -216,6 +217,7 @@ public: uint has_pen : 1; uint has_brush : 1; uint has_custom_paper_size : 1; + uint embed_fonts : 1; uint txop; diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp index c13b1574d0..437a68e609 100644 --- a/src/printsupport/kernel/qprinter.cpp +++ b/src/printsupport/kernel/qprinter.cpp @@ -1632,8 +1632,6 @@ QPrinter::PaperSource QPrinter::paperSource() const Enabled or disables font embedding depending on \a enable. - Currently this option is only supported on X11. - \sa fontEmbeddingEnabled() */ void QPrinter::setFontEmbeddingEnabled(bool enable) @@ -1647,8 +1645,6 @@ void QPrinter::setFontEmbeddingEnabled(bool enable) Returns \c true if font embedding is enabled. - Currently this option is only supported on X11. - \sa setFontEmbeddingEnabled() */ bool QPrinter::fontEmbeddingEnabled() const diff --git a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp index 1be570e4b8..e3a72f4ab4 100644 --- a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp +++ b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp @@ -1103,9 +1103,7 @@ void tst_QPrinter::fontEmbedding() { // fontEmbeddingEnabled() / setFontEmbeddingEnabled() / PPK_FontEmbedding // PdfFormat: Supported, default true - // NativeFormat, Cups: Supported, default true - // NativeFormat, Win: Unsupported, always false - // NativeFormat, Mac: Unsupported, always false + // NativeFormat: Supported, default true QPrinter pdf; pdf.setOutputFormat(QPrinter::PdfFormat); @@ -1116,25 +1114,17 @@ void tst_QPrinter::fontEmbedding() QPrinter native; if (native.outputFormat() == QPrinter::NativeFormat) { // Test default -#if defined Q_OS_MAC || defined Q_OS_WIN - QCOMPARE(native.fontEmbeddingEnabled(), false); -#else QCOMPARE(native.fontEmbeddingEnabled(), true); -#endif // Q_OS_MAC || Q_OS_WIN // Test set/get - bool expected = true; - native.setFontEmbeddingEnabled(expected); -#if defined Q_OS_MAC || defined Q_OS_WIN - expected = false; -#endif // Q_OS_MAC || Q_OS_WIN - QCOMPARE(native.fontEmbeddingEnabled(), expected); + native.setFontEmbeddingEnabled(true); + QCOMPARE(native.fontEmbeddingEnabled(), true); // Test value preservation native.setOutputFormat(QPrinter::PdfFormat); - QCOMPARE(native.fontEmbeddingEnabled(), expected); + QCOMPARE(native.fontEmbeddingEnabled(), true); native.setOutputFormat(QPrinter::NativeFormat); - QCOMPARE(native.fontEmbeddingEnabled(), expected); + QCOMPARE(native.fontEmbeddingEnabled(), true); } else { QSKIP("No printers installed, cannot test NativeFormat, please install printers to test"); } From 946cf4ca00dbcdc15d24dc2b52bf01c69dcda848 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 11 Nov 2014 08:27:10 +0200 Subject: [PATCH 251/323] Android: copy build.gradle to install folder. Task-number: QTCREATORBUG-13311 Change-Id: I4c91164ae1fc593397bb46f98fbc49ef1569da39 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/android/templates/templates.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/android/templates/templates.pro b/src/android/templates/templates.pro index 684a556c5b..55387f3af7 100644 --- a/src/android/templates/templates.pro +++ b/src/android/templates/templates.pro @@ -2,6 +2,7 @@ CONFIG -= qt android_install templates.files = \ $$PWD/AndroidManifest.xml \ + $$PWD/build.gradle \ $$PWD/res templates.path = $$[QT_INSTALL_PREFIX]/src/android/templates @@ -17,5 +18,6 @@ INSTALLS += templates QMAKE_POST_LINK += \ $${QMAKE_COPY} $$shell_path($$PWD/AndroidManifest.xml) $$OUT_PATH $$RETURN \ + $${QMAKE_COPY} $$shell_path($$PWD/build.gradle) $$OUT_PATH $$RETURN \ $${QMAKE_COPY_DIR} $$shell_path($$PWD/res) $$OUT_PATH } From dfbd09378c203ce029adf4a31f3a755cf22fb2e8 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 14 Nov 2014 13:01:13 +0200 Subject: [PATCH 252/323] Fix crash on Android L and list view items. This crash is visible on Android L. This patch removes the static_cast which caused the crash and it also fixed the list view item problem. I could not create separated patches because they depend too much on each other. Task-number: QTBUG-42673 Task-number: QTBUG-41814 Change-Id: I5d3e9c2b73df8f0e87e815b785b1c64d65a3ffaf Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/widgets/styles/qandroidstyle.cpp | 112 ++++++++++----------------- src/widgets/styles/qandroidstyle_p.h | 8 +- 2 files changed, 42 insertions(+), 78 deletions(-) diff --git a/src/widgets/styles/qandroidstyle.cpp b/src/widgets/styles/qandroidstyle.cpp index 0bc0b4f087..337da24aee 100644 --- a/src/widgets/styles/qandroidstyle.cpp +++ b/src/widgets/styles/qandroidstyle.cpp @@ -244,6 +244,10 @@ QAndroidStyle::ItemType QAndroidStyle::qtControl(QStyle::PrimitiveElement primit case QStyle::PE_FrameLineEdit: return QC_EditText; + case QStyle::PE_IndicatorViewItemCheck: + case QStyle::PE_IndicatorCheckBox: + return QC_Checkbox; + case QStyle::PE_FrameWindow: case QStyle::PE_Widget: case QStyle::PE_Frame: @@ -357,37 +361,8 @@ void QAndroidStyle::drawControl(QStyle::ControlElement element, } break; default: - break; - } - } else if (element == CE_ItemViewItem) { - const QStyleOptionViewItem *vopt = qstyleoption_cast(opt); - if (vopt && vopt->features & QStyleOptionViewItem::HasCheckIndicator) { - p->save(); - p->setClipRect(opt->rect); - - QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, w); - - // draw the background - proxy()->drawPrimitive(PE_PanelItemViewItem, opt, p, w); - - // draw the check mark - QStyleOptionViewItem option(*vopt); - option.rect = checkRect; - option.state = option.state & ~QStyle::State_HasFocus; - - switch (vopt->checkState) { - case Qt::Unchecked: - option.state |= QStyle::State_Off; - break; - default: - option.state |= QStyle::State_On; - break; - } - QPixmap pixmap = checkBoxControl->imgCheckBox(&option); - p->drawPixmap(checkRect, pixmap); - p->restore(); - } else { QFusionStyle::drawControl(element, opt, p, w); + break; } } else { QFusionStyle::drawControl(element, opt, p, w); @@ -532,7 +507,7 @@ QRect QAndroidStyle::subControlRect(ComplexControl cc, case CC_GroupBox: { if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { QSize textSize = opt->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); - QSize checkBoxSize = checkBoxControl->sizeCheckBox(opt); + QSize checkBoxSize = checkBoxControl->size(opt); int indicatorWidth = checkBoxSize.width(); int indicatorHeight = checkBoxSize.height(); QRect checkBoxRect; @@ -589,9 +564,9 @@ int QAndroidStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, case PM_ScrollBarExtent: return 0; case PM_IndicatorWidth: - return checkBoxControl->sizeCheckBox(option).width(); + return checkBoxControl->size(option).width(); case PM_IndicatorHeight: - return checkBoxControl->sizeCheckBox(option).height(); + return checkBoxControl->size(option).height(); default: return QFusionStyle::pixelMetric(metric, option, widget); } @@ -608,7 +583,7 @@ QSize QAndroidStyle::sizeFromContents(ContentsType ct, if (const QStyleOptionHeader *hdr = qstyleoption_cast(opt)) { bool nullIcon = hdr->icon.isNull(); int margin = pixelMetric(QStyle::PM_HeaderMargin, hdr, w); - int iconSize = nullIcon ? 0 : checkBoxControl->sizeCheckBox(opt).width(); + int iconSize = nullIcon ? 0 : checkBoxControl->size(opt).width(); QSize txt; /* * These next 4 lines are a bad hack to fix a bug in case a QStyleSheet is applied at QApplication level. @@ -642,7 +617,7 @@ QSize QAndroidStyle::sizeFromContents(ContentsType ct, if (ct == CT_GroupBox) { if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast(opt)) { QSize textSize = opt->fontMetrics.boundingRect(groupBox->text).size() + QSize(2, 2); - QSize checkBoxSize = checkBoxControl->sizeCheckBox(opt); + QSize checkBoxSize = checkBoxControl->size(opt); int indicatorWidth = checkBoxSize.width(); int indicatorHeight = checkBoxSize.height(); QRect checkBoxRect; @@ -738,13 +713,6 @@ QSize QAndroidStyle::AndroidDrawable::size() const return QSize(); } -QPixmap QAndroidStyle::AndroidDrawable::img() const -{ - if (type() == Image || type() == NinePatch) - return static_cast(this)->img(); - - return QPixmap(); -} QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidDrawable::fromMap(const QVariantMap &drawable, ItemType itemType) @@ -810,19 +778,7 @@ void QAndroidStyle::AndroidImageDrawable::draw(QPainter *painter, const QStyleOp QPixmapCache::insert(m_hashKey, pm); } - painter->drawPixmap(opt->rect.x(), (opt->rect.height() - pm.height()) / 2, pm); -} -QPixmap QAndroidStyle::AndroidImageDrawable::img() const -{ - if (m_hashKey.isEmpty()) - m_hashKey = QFileInfo(m_filePath).fileName(); - - QPixmap pm; - if (!QPixmapCache::find(m_hashKey, &pm)) { - pm.load(m_filePath); - QPixmapCache::insert(m_hashKey, pm); - } - return pm; + painter->drawPixmap(opt->rect.x(), opt->rect.y() + (opt->rect.height() - pm.height()) / 2, pm); } QSize QAndroidStyle::AndroidImageDrawable::size() const @@ -1220,14 +1176,6 @@ QSize QAndroidStyle::AndroidStateDrawable::sizeImage(const QStyleOption *opt) co s = drawable->size(); return s; } -QPixmap QAndroidStyle::AndroidStateDrawable::img(const QStyleOption *opt) const -{ - QPixmap pm; - const AndroidDrawable *drawable = bestAndroidStateMatch(opt); - if (drawable) - pm = drawable->img(); - return pm; -} const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidStateDrawable::bestAndroidStateMatch(const QStyleOption *opt) const { @@ -1507,7 +1455,6 @@ QRect QAndroidStyle::AndroidControl::subElementRect(QStyle::SubElement /* subEle return visualRect(option->direction, option->rect, r); } return option->rect; - } QRect QAndroidStyle::AndroidControl::subControlRect(const QStyleOptionComplex *option, @@ -1552,6 +1499,16 @@ QMargins QAndroidStyle::AndroidControl::padding() return QMargins(); } +QSize QAndroidStyle::AndroidControl::size(const QStyleOption *option) +{ + if (const AndroidDrawable *drawable = backgroundDrawable()) { + if (drawable->type() == State) + drawable = static_cast(backgroundDrawable())->bestAndroidStateMatch(option); + return drawable->size(); + } + return QSize(); +} + const QAndroidStyle::AndroidDrawable *QAndroidStyle::AndroidControl::backgroundDrawable() const { return m_background; @@ -1562,11 +1519,12 @@ QAndroidStyle::AndroidCompoundButtonControl::AndroidCompoundButtonControl(const : AndroidControl(control, itemType) { QVariantMap::const_iterator it = control.find(QLatin1String("CompoundButton_button")); - if (it != control.end()) + if (it != control.end()) { m_button = AndroidDrawable::fromMap(it.value().toMap(), itemType); - else + const_cast(m_button)->setPaddingLeftToSizeWidth(); + } else { m_button = 0; - const_cast(m_button)->setPaddingLeftToSizeWidth(); + } } QAndroidStyle::AndroidCompoundButtonControl::~AndroidCompoundButtonControl() @@ -1582,16 +1540,24 @@ void QAndroidStyle::AndroidCompoundButtonControl::drawControl(const QStyleOption if (m_button) m_button->draw(p, opt); } -QSize QAndroidStyle::AndroidCompoundButtonControl::sizeCheckBox(const QStyleOption *opt) const + +QMargins QAndroidStyle::AndroidCompoundButtonControl::padding() { - const AndroidDrawable *drawable = m_button; - return static_cast(drawable)->sizeImage(opt); + if (m_button) + return m_button->padding(); + return AndroidControl::padding(); } -QPixmap QAndroidStyle::AndroidCompoundButtonControl::imgCheckBox(const QStyleOption *opt) const + +QSize QAndroidStyle::AndroidCompoundButtonControl::size(const QStyleOption *option) { - const AndroidDrawable *drawable = m_button; - return static_cast(drawable)->img(opt); + if (m_button) { + if (m_button->type() == State) + return static_cast(m_button)->bestAndroidStateMatch(option)->size(); + return m_button->size(); + } + return AndroidControl::size(option); } + const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidCompoundButtonControl::backgroundDrawable() const { return m_background ? m_background : m_button; diff --git a/src/widgets/styles/qandroidstyle_p.h b/src/widgets/styles/qandroidstyle_p.h index 504d43fe96..d8e7768380 100644 --- a/src/widgets/styles/qandroidstyle_p.h +++ b/src/widgets/styles/qandroidstyle_p.h @@ -124,7 +124,6 @@ public: static AndroidDrawable *fromMap(const QVariantMap &drawable, ItemType itemType); static QMargins extractMargins(const QVariantMap &value); virtual void setPaddingLeftToSizeWidth(); - QPixmap img() const; protected: ItemType m_itemType; QMargins m_padding; @@ -149,7 +148,6 @@ public: virtual void draw(QPainter *painter,const QStyleOption *opt) const; virtual QSize size() const; - QPixmap img() const; protected: QString m_filePath; mutable QString m_hashKey; @@ -223,7 +221,6 @@ public: static int extractState(const QVariantMap &value); virtual void setPaddingLeftToSizeWidth(); QSize sizeImage(const QStyleOption *opt) const; - QPixmap img(const QStyleOption *opt) const; private: typedef QPair StateType; QList m_states; @@ -263,6 +260,7 @@ public: const QSize &contentsSize, const QWidget *w) const; virtual QMargins padding(); + virtual QSize size(const QStyleOption *option); protected: virtual const AndroidDrawable * backgroundDrawable() const; const AndroidDrawable *m_background; @@ -276,8 +274,8 @@ public: AndroidCompoundButtonControl(const QVariantMap &control, ItemType itemType); virtual ~AndroidCompoundButtonControl(); virtual void drawControl(const QStyleOption *opt, QPainter *p, const QWidget *w); - QSize sizeCheckBox(const QStyleOption *opt) const; - QPixmap imgCheckBox(const QStyleOption *opt) const; + virtual QMargins padding(); + virtual QSize size(const QStyleOption *option); protected: virtual const AndroidDrawable * backgroundDrawable() const; const AndroidDrawable *m_button; From 08afe17731001a87569a17ad0fa9974e9dc88f19 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 14 Nov 2014 13:02:59 +0200 Subject: [PATCH 253/323] Android: Fix QSlider appearance Task-number: QTBUG-42672 Change-Id: I882c1f625ea659967a8db09246dc28d7aef93fdf Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/widgets/styles/qandroidstyle.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/widgets/styles/qandroidstyle.cpp b/src/widgets/styles/qandroidstyle.cpp index 337da24aee..5b4b346da9 100644 --- a/src/widgets/styles/qandroidstyle.cpp +++ b/src/widgets/styles/qandroidstyle.cpp @@ -1648,7 +1648,6 @@ QRect QAndroidStyle::AndroidProgressBarControl::subElementRect(QStyle::SubElemen p |= QRect(padding.left(), padding.top(), padding.right() - padding.left(), padding.bottom() - padding.top()); padding = m_progressDrawable->padding(); p |= QRect(padding.left(), padding.top(), padding.right() - padding.left(), padding.bottom() - padding.top()); - QRect r = option->rect.adjusted(p.left(), p.top(), -p.right(), -p.bottom()); if (horizontal) { @@ -1731,15 +1730,15 @@ void QAndroidStyle::AndroidSeekBarControl::drawControl(const QStyleOption *optio if (drawable->type() == State) drawable = static_cast(m_seekBarThumb)->bestAndroidStateMatch(option); QStyleOption copy(*option); - copy.rect.setY((copy.rect.height() - m_minSize.height()) / 2); - copy.rect.setHeight(m_minSize.height()); + copy.rect.setHeight(m_progressDrawable->size().height()); copy.rect.setWidth(copy.rect.width() - drawable->size().width()); - copy.rect.translate(drawable->size().width() / 2, 0); + const int yTranslate = abs(drawable->size().height() - copy.rect.height()) / 2; + copy.rect.translate(drawable->size().width() / 2, yTranslate); m_progressDrawable->draw(p, ©); if (styleOption->orientation == Qt::Vertical) qCritical() << "Vertical slider are not supported"; - int pos = copy.rect.width()*factor - drawable->size().width() / 2; - copy.rect.translate(pos, 0); + int pos = copy.rect.width() * factor - drawable->size().width() / 2; + copy.rect.translate(pos, -yTranslate); copy.rect.setSize(drawable->size()); m_seekBarThumb->draw(p, ©); } From 47c2d76dbab76fc33ca6c73ac701d6814d861f89 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Fri, 14 Nov 2014 11:51:49 +0200 Subject: [PATCH 254/323] winrt: Resize window on Windows Phone using EGL To avoid duplicating code in ANGLE, we can resize the framebuffer in QPA. This potentially allows us to synchronize rendering to avoid displaying a frame which is rendered for the new geometry but is displayed with the old geometry. Change-Id: I5f3a0634628d9ea4ca73349a02e646eb043bd757 Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 46 ++++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 681307ddcf..fadcd01b06 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -473,6 +473,7 @@ QWinRTScreen::QWinRTScreen() Q_D(QWinRTScreen); d->orientation = Qt::PrimaryOrientation; d->touchDevice = Q_NULLPTR; + d->eglDisplay = EGL_NO_DISPLAY; // Obtain the WinRT Application, view, and window HRESULT hr; @@ -531,8 +532,10 @@ QWinRTScreen::QWinRTScreen() Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); +#ifndef Q_OS_WINPHONE hr = d->coreWindow->add_SizeChanged(Callback(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); Q_ASSERT_SUCCEEDED(hr); +#endif hr = d->coreWindow->add_Activated(Callback(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_Closed(Callback(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); @@ -610,7 +613,14 @@ QWinRTScreen::QWinRTScreen() d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); + const QRect bounds = geometry(); + EGLint windowAttributes[] = { + EGL_FIXED_SIZE_ANGLE, EGL_TRUE, + EGL_WIDTH, bounds.width(), + EGL_HEIGHT, bounds.height(), + EGL_NONE + }; + d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), windowAttributes); if (d->eglSurface == EGL_NO_SURFACE) qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); } @@ -1051,26 +1061,33 @@ HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationPr return S_OK; } -HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *args) +HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) { Q_D(QWinRTScreen); - Size size; - HRESULT hr = args->get_Size(&size); - RETURN_OK_IF_FAILED("Failed to get window size."); - + Rect size; + HRESULT hr; + hr = d->coreWindow->get_Bounds(&size); + RETURN_OK_IF_FAILED("Failed to get window bounds"); QSizeF logicalSize = QSizeF(size.Width, size.Height); +#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size if (d->logicalSize == logicalSize) return S_OK; +#endif - // Regardless of state, all top-level windows are viewport-sized - this might change if - // a more advanced compositor is written. d->logicalSize = logicalSize; - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); - QPlatformScreen::resizeMaximizedWindows(); - handleExpose(); - + if (d->eglDisplay) { + const QRect newGeometry = geometry(); +#ifdef Q_OS_WINPHONE // Resize the EGL window + const int width = newGeometry.width() * (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::LandscapeOrientation ? -1 : 1); + const int height = newGeometry.height() * (d->orientation == Qt::InvertedPortraitOrientation || d->orientation == Qt::InvertedLandscapeOrientation ? -1 : 1); + eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_WIDTH, width); + eglSurfaceAttrib(d->eglDisplay, d->eglSurface, EGL_HEIGHT, height); +#endif + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); + } return S_OK; } @@ -1140,6 +1157,9 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } +#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback + onSizeChanged(Q_NULLPTR, Q_NULLPTR); +#endif return S_OK; } From f44eb5c57f28825e29425be339a00df5d99b68eb Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 17 Oct 2014 13:46:37 +0200 Subject: [PATCH 255/323] Doc: Solved link and autolink errs qnamespace.qdoc Task-number: QTBUG-40362 Change-Id: I81166dc3a54427e2d2d81f640162f6c338947849 Reviewed-by: Martin Smith --- src/corelib/global/qnamespace.qdoc | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 4e074bcdb5..8d6f7834b0 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -134,7 +134,7 @@ \value AA_MacDontSwapCtrlAndMeta On Mac OS X by default, Qt swaps the Control and Meta (Command) keys (i.e., whenever Control is pressed, Qt sends Meta, and whenever Meta is pressed Control is sent). When this - attribute is true, Qt will not do the flip. QKeySequence::StandardShortcuts + attribute is true, Qt will not do the flip. \l QKeySequence::StandardKey will also flip accordingly (i.e., QKeySequence::Copy will be Command+C on the keyboard regardless of the value set, though what is output for QKeySequence::toString(QKeySequence::PortableText) will be different). @@ -144,7 +144,7 @@ to be consistent in pixels-per-point across devices rather than defining 1 point as 1/72 inch. - \value AA_X11InitThreads Calls XInitThreads() as part of the QApplication + \value AA_X11InitThreads Calls \c XInitThreads() as part of the QApplication construction in order to make Xlib calls thread-safe. This attribute must be set before QApplication is constructed. @@ -159,10 +159,11 @@ \value AA_UseHighDpiPixmaps Make QIcon::pixmap() generate high-dpi pixmaps that can be larger than the requested size. Such pixmaps will have - devicePixelRatio set to a value higher than 1. After setting this - attribute application code that uses pixmap sizes in layout geometry - calculations should typically divide by QPixmap::devicePixelRatio() - to get device-independent layout geometry. + \l {QPixmap::devicePixelRatio}{devicePixelRatio()} set to a value higher than 1. + + After setting this attribute, application code that uses pixmap + sizes in layout geometry calculations should typically divide by + \l {QPixmap::devicePixelRatio}{devicePixelRatio()} to get device-independent layout geometry. \value AA_ForceRasterWidgets Make top-level widgets use pure raster surfaces, and do not support non-native GL-based child widgets. @@ -182,7 +183,7 @@ \l{http://www.mesa3d.org/llvmpipe.html}{Mesa llvmpipe}, providing OpenGL 2.1. The value may have no effect if no such OpenGL implementation is available. The default name of this library is - opengl32sw.dll and can be overridden by setting the environment + \c opengl32sw.dll and can be overridden by setting the environment variable \e QT_OPENGL_DLL. See the platform-specific pages, for instance \l{Qt for Windows}, for more information. This value has been added in Qt 5.4. @@ -221,7 +222,7 @@ \value AllButtons This value corresponds to a mask of all possible mouse buttons. Use to set the 'acceptedButtons' - property of a mouseArea to accept ALL mouse buttons. + property of a MouseArea to accept ALL mouse buttons. \value LeftButton The left button is pressed, or an event refers to the left button. (The left button may be the right button on @@ -2443,7 +2444,7 @@ \value ImhExclusiveInputMask This mask yields nonzero if any of the exclusive flags are used. - \note If several exclusive flags are ORed together, the resulting character set will + \note If several exclusive flags are OR-ed together, the resulting character set will consist of the union of the specified sets. For instance specifying \c ImhNumbersOnly and \c ImhUppercaseOnly would yield a set consisting of numbers and uppercase letters. @@ -2969,8 +2970,8 @@ This enum provides additional information concerning a QMouseEvent. \value MouseEventCreatedDoubleClick Indicates that Qt has created a - MouseButtonDblClick event from this event. The flag is set in the causing - MouseButtonPress, and not in the resulting MouseButtonDblCLick. + \l {QEvent::MouseButtonDblClick}{MouseButtonDblClick} event from this event. The flag is set in the causing + \l {QEvent::MouseButtonPress}{MouseButtonPress}, and not in the resulting \l {QEvent::MouseButtonDblClick}{MouseButtonDblClick}. \omitvalue MouseEventFlagMask */ From 0600f7d6299a21014f1b72d54fc6b23c02693204 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 14 Nov 2014 14:15:04 +0400 Subject: [PATCH 256/323] Fix hb_face leaking in QFontEngineFT Since HarfBuzz-old's HB_Face doesn't support ref-counting, it is impossible to keep the same behavior as for NG's ref-counted hb_face when we're going to reparent the data of unknown type in QFontEngineFT. We should either not release the object returned by harfbuzzFace(), or introduce ref-counting for HB-old's HB_Face. Stop referencing HB-NG's objects on access for now and thus avoid a need to release them manually. Task-number: QTBUG-42674 Change-Id: Ia21e7ba9c17185796b0dd98c2c27d02566f2a701 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfontengine.cpp | 2 -- src/gui/text/qharfbuzzng.cpp | 6 ++---- src/gui/text/qtextengine.cpp | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 52e10bd717..0b517fbf29 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -373,8 +373,6 @@ bool QFontEngine::supportsScript(QChar::Script script) const if (!ret && script_tag_2 != HB_OT_TAG_DEFAULT_SCRIPT) ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, HB_OT_TAG_DEFAULT_SCRIPT, &script_index); } - - hb_face_destroy(face); } return ret; } diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index eb7bca1974..16c45e642b 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -632,7 +632,7 @@ hb_face_t *hb_qt_face_get_for_engine(QFontEngine *fe) fe->face_destroy_func = _hb_qt_face_release; } - return hb_face_reference((hb_face_t *)fe->face_); + return (hb_face_t *)fe->face_; } @@ -645,8 +645,6 @@ _hb_qt_font_create(QFontEngine *fe) hb_font_t *font = hb_font_create(face); - hb_face_destroy(face); // ref-ed in hb_qt_face_get_for_engine() - if (Q_UNLIKELY(hb_font_is_immutable(font))) { hb_font_destroy(font); return NULL; @@ -684,7 +682,7 @@ hb_font_t *hb_qt_font_get_for_engine(QFontEngine *fe) fe->font_destroy_func = _hb_qt_font_release; } - return hb_font_reference((hb_font_t *)fe->font_); + return (hb_font_t *)fe->font_; } QT_END_NAMESPACE diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 9fe1fd26e9..d156124b98 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1168,8 +1168,6 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st }; const int num_features = 1; shapedOk = hb_shape_full(hb_font, buffer, features, num_features, 0); - - hb_font_destroy(hb_font); } if (!shapedOk) { hb_buffer_destroy(buffer); From 2b9ae07ca3fef1178b63d5052c33edf6b5551f5c Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 13 Nov 2014 15:43:08 +0200 Subject: [PATCH 257/323] Android: Extract VectorDrawable Task-numer: QTBUG-42488 Change-Id: Iacc9e6afc75f1f480ba8119c9cbd481beb1d1089 Reviewed-by: J-P Nurmi Reviewed-by: BogDan Vatra --- .../qtproject/qt5/android/ExtractStyle.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 4dbc33057b..a8583cde17 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -99,6 +99,7 @@ public class ExtractStyle { Class styleableClass = getClass("android.R$styleable"); Class rippleDrawableClass = getClass("android.graphics.drawable.RippleDrawable"); Class animatedStateListDrawableClass = getClass("android.graphics.drawable.AnimatedStateListDrawable"); + Class vectorDrawableClass = getClass("android.graphics.drawable.VectorDrawable"); final int[] EMPTY_STATE_SET = {}; final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled}; @@ -410,6 +411,24 @@ public class ExtractStyle { return null; } + Field tryGetAccessibleField(Class clazz, String fieldName) { + if (clazz == null) + return null; + + try { + Field f = clazz.getDeclaredField(fieldName); + f.setAccessible(true); + return f; + } catch (Exception e) { + for (Class c : clazz.getInterfaces()) { + Field f = tryGetAccessibleField(c, fieldName); + if (f != null) + return f; + } + } + return tryGetAccessibleField(clazz.getSuperclass(), fieldName); + } + int getField(Class clazz, String fieldName) { try { @@ -873,6 +892,95 @@ public class ExtractStyle { return json; } + private JSONObject getVPath(Object path) throws Exception + { + JSONObject json = new JSONObject(); + final Class pathClass = path.getClass(); + json.put("type", "path"); + json.put("name", tryGetAccessibleField(pathClass, "mPathName").get(path)); + Object[] mNodes = (Object[]) tryGetAccessibleField(pathClass, "mNodes").get(path); + JSONArray nodes = new JSONArray(); + for (Object n: mNodes) { + JSONObject node = new JSONObject(); + node.put("type", String.valueOf(getAccessibleField(n.getClass(), "mType").getChar(n))); + node.put("params", getJsonArray((float[])getAccessibleField(n.getClass(), "mParams").get(n))); + nodes.put(node); + } + json.put("nodes", nodes); + json.put("isClip", (Boolean) pathClass.getMethod("isClipPath").invoke(path)); + + if (tryGetAccessibleField(pathClass, "mStrokeColor") == null) + return json; // not VFullPath + + json.put("strokeColor", getAccessibleField(pathClass, "mStrokeColor").getInt(path)); + json.put("strokeWidth", getAccessibleField(pathClass, "mStrokeWidth").getFloat(path)); + json.put("fillColor", getAccessibleField(pathClass, "mFillColor").getInt(path)); + json.put("strokeAlpha", getAccessibleField(pathClass, "mStrokeAlpha").getFloat(path)); + json.put("fillRule", getAccessibleField(pathClass, "mFillRule").getInt(path)); + json.put("fillAlpha", getAccessibleField(pathClass, "mFillAlpha").getFloat(path)); + json.put("trimPathStart", getAccessibleField(pathClass, "mTrimPathStart").getFloat(path)); + json.put("trimPathEnd", getAccessibleField(pathClass, "mTrimPathEnd").getFloat(path)); + json.put("trimPathOffset", getAccessibleField(pathClass, "mTrimPathOffset").getFloat(path)); + json.put("strokeLineCap", (Paint.Cap) getAccessibleField(pathClass, "mStrokeLineCap").get(path)); + json.put("strokeLineJoin", (Paint.Join) getAccessibleField(pathClass, "mStrokeLineJoin").get(path)); + json.put("strokeMiterlimit", getAccessibleField(pathClass, "mStrokeMiterlimit").getFloat(path)); + return json; + } + + @SuppressWarnings("unchecked") + private JSONObject getVGroup(Object group) throws Exception + { + JSONObject json = new JSONObject(); + json.put("type", "group"); + final Class groupClass = group.getClass(); + json.put("name", getAccessibleField(groupClass, "mGroupName").get(group)); + json.put("rotate", getAccessibleField(groupClass, "mRotate").getFloat(group)); + json.put("pivotX", getAccessibleField(groupClass, "mPivotX").getFloat(group)); + json.put("pivotY", getAccessibleField(groupClass, "mPivotY").getFloat(group)); + json.put("scaleX", getAccessibleField(groupClass, "mScaleX").getFloat(group)); + json.put("scaleY", getAccessibleField(groupClass, "mScaleY").getFloat(group)); + json.put("translateX", getAccessibleField(groupClass, "mTranslateX").getFloat(group)); + json.put("translateY", getAccessibleField(groupClass, "mTranslateY").getFloat(group)); + + ArrayList mChildren = (ArrayList) getAccessibleField(groupClass, "mChildren").get(group); + JSONArray children = new JSONArray(); + for (Object c: mChildren) { + if (groupClass.isInstance(c)) + children.put(getVGroup(c)); + else + children.put(getVPath(c)); + } + json.put("children", children); + return json; + } + + private JSONObject getVectorDrawable(Object drawable, String filename, Rect padding) + { + JSONObject json = new JSONObject(); + try { + json.put("type", "vector"); + final Object state = getAccessibleField(vectorDrawableClass, "mVectorState").get(drawable); + final Class stateClass = state.getClass(); + final ColorStateList mTint = (ColorStateList) getAccessibleField(stateClass, "mTint").get(state); + if (mTint != null) { + json.put("tintList", getColorStateList(mTint)); + json.put("tintMode", (PorterDuff.Mode) getAccessibleField(stateClass, "mTintMode").get(state)); + } + final Object mVPathRenderer = getAccessibleField(stateClass, "mVPathRenderer").get(state); + final Class VPathRendererClass = mVPathRenderer.getClass(); + json.put("baseWidth", getAccessibleField(VPathRendererClass, "mBaseWidth").getFloat(mVPathRenderer)); + json.put("baseHeight", getAccessibleField(VPathRendererClass, "mBaseHeight").getFloat(mVPathRenderer)); + json.put("viewportWidth", getAccessibleField(VPathRendererClass, "mViewportWidth").getFloat(mVPathRenderer)); + json.put("viewportHeight", getAccessibleField(VPathRendererClass, "mViewportHeight").getFloat(mVPathRenderer)); + json.put("rootAlpha", getAccessibleField(VPathRendererClass, "mRootAlpha").getInt(mVPathRenderer)); + json.put("rootName", getAccessibleField(VPathRendererClass, "mRootName").get(mVPathRenderer)); + json.put("rootGroup", getVGroup(getAccessibleField(mVPathRenderer.getClass(), "mRootGroup").get(mVPathRenderer))); + } catch(Exception e) { + e.printStackTrace(); + } + return json; + } + public JSONObject getDrawable(Object drawable, String filename, Rect padding) { if (drawable == null) @@ -922,6 +1030,9 @@ public class ExtractStyle { if (animatedStateListDrawableClass != null && animatedStateListDrawableClass.isInstance(drawable)) return getAnimatedStateListDrawable(drawable, filename); + if (vectorDrawableClass != null && vectorDrawableClass.isInstance(drawable)) + return getVectorDrawable(drawable, filename, padding); + if (drawable instanceof ScaleDrawable) { return getDrawable(((ScaleDrawable)drawable).getDrawable(), filename, null); From db31a5009af21719c040b7f203c32fd821ae011e Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Tue, 11 Nov 2014 14:17:27 +0100 Subject: [PATCH 258/323] WinRT: Fill data in QUdpSocket::readDatagram There was still a TODO left in there and the data was never filled. In addition to filling the data, some pointer checks for addr and port were added. Task-number: QTBUG-42244 Change-Id: I8e358b5544edcdb4077a52f433e4bc17d92014ce Reviewed-by: Andrew Knight --- .../socket/qnativesocketengine_winrt.cpp | 88 ++++++++++--------- .../socket/qnativesocketengine_winrt_p.h | 9 +- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index c3be3eb408..cacfe11fea 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -529,41 +529,27 @@ qint64 QNativeSocketEngine::write(const char *data, qint64 len) qint64 QNativeSocketEngine::readDatagram(char *data, qint64 maxlen, QHostAddress *addr, quint16 *port) { Q_D(QNativeSocketEngine); - if (d->socketType != QAbstractSocket::UdpSocket) + if (d->socketType != QAbstractSocket::UdpSocket || d->pendingDatagrams.isEmpty()) return -1; - QHostAddress returnAddress; - quint16 returnPort; + WinRtDatagram datagram = d->pendingDatagrams.takeFirst(); + if (addr) + *addr = datagram.address; - for (int i = 0; i < d->pendingDatagrams.size(); ++i) { - IDatagramSocketMessageReceivedEventArgs *arg = d->pendingDatagrams.at(i); - ComPtr remoteHost; - HString remoteHostString; - HString remotePort; - arg->get_RemoteAddress(&remoteHost); - arg->get_RemotePort(remotePort.GetAddressOf()); - remoteHost->get_CanonicalName(remoteHostString.GetAddressOf()); - returnAddress.setAddress(qt_QStringFromHString(remoteHostString)); - returnPort = qt_QStringFromHString(remotePort).toInt(); - ComPtr reader; - arg->GetDataReader(&reader); - if (!reader) - continue; + if (port) + *port = datagram.port; - BYTE buffer[1024]; - reader->ReadBytes(maxlen, buffer); - *addr = returnAddress; - *port = returnPort; - arg = d->pendingDatagrams.takeFirst(); - arg->Release(); - - // TODO: fill data - Q_UNUSED(data); - --i; - return maxlen; + QByteArray readOrigin; + // Do not read the whole datagram. Put the rest of it back into the "queue" + if (maxlen < datagram.data.length()) { + QByteArray readOrigin = datagram.data.left(maxlen); + datagram.data = datagram.data.remove(0, maxlen); + d->pendingDatagrams.prepend(datagram); + } else { + readOrigin = datagram.data; } - - return -1; + strcpy(data, readOrigin); + return readOrigin.length(); } qint64 QNativeSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &addr, quint16 port) @@ -609,17 +595,10 @@ bool QNativeSocketEngine::hasPendingDatagrams() const qint64 QNativeSocketEngine::pendingDatagramSize() const { Q_D(const QNativeSocketEngine); - qint64 ret = 0; - foreach (IDatagramSocketMessageReceivedEventArgs *arg, d->pendingDatagrams) { - ComPtr reader; - UINT32 unconsumedBufferLength; - arg->GetDataReader(&reader); - if (!reader) - return -1; - reader->get_UnconsumedBufferLength(&unconsumedBufferLength); - ret += unconsumedBufferLength; - } - return ret; + if (d->pendingDatagrams.isEmpty()) + return -1; + + return d->pendingDatagrams.at(0).data.length(); } qint64 QNativeSocketEngine::bytesToWrite() const @@ -1236,7 +1215,32 @@ HRESULT QNativeSocketEnginePrivate::handleNewDatagram(IDatagramSocket *socket, I { Q_Q(QNativeSocketEngine); Q_UNUSED(socket); - pendingDatagrams.append(args); + + WinRtDatagram datagram; + QHostAddress returnAddress; + ComPtr remoteHost; + HRESULT hr = args->get_RemoteAddress(&remoteHost); + RETURN_OK_IF_FAILED("Could not obtain remote host"); + HString remoteHostString; + remoteHost->get_CanonicalName(remoteHostString.GetAddressOf()); + RETURN_OK_IF_FAILED("Could not obtain remote host's canonical name"); + returnAddress.setAddress(qt_QStringFromHString(remoteHostString)); + datagram.address = returnAddress; + HString remotePort; + hr = args->get_RemotePort(remotePort.GetAddressOf()); + RETURN_OK_IF_FAILED("Could not obtain remote port"); + datagram.port = qt_QStringFromHString(remotePort).toInt(); + + ComPtr reader; + hr = args->GetDataReader(&reader); + RETURN_OK_IF_FAILED("Could not obtain data reader"); + quint32 length; + hr = reader->get_UnconsumedBufferLength(&length); + RETURN_OK_IF_FAILED("Could not obtain unconsumed buffer length"); + datagram.data.resize(length); + hr = reader->ReadBytes(length, reinterpret_cast(datagram.data.data())); + RETURN_OK_IF_FAILED("Could not read datagram"); + pendingDatagrams.append(datagram); emit q->readReady(); return S_OK; diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 7652a09b17..716403097d 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -55,6 +55,12 @@ QT_BEGIN_NAMESPACE class QNativeSocketEnginePrivate; +struct WinRtDatagram { + QByteArray data; + int port; + QHostAddress address; +}; + class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine { Q_OBJECT @@ -197,7 +203,8 @@ private: Microsoft::WRL::ComPtr connectOp; QBuffer readBytes; QMutex readMutex; - QList pendingDatagrams; + + QList pendingDatagrams; QList pendingConnections; QList currentConnections; QEventLoop eventLoop; From 954552ceac4a04bebc56d2f7f3464568ef671cb1 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 14 Nov 2014 13:57:55 +0100 Subject: [PATCH 259/323] Update fbo toImage() docs regarding premultiplied alpha Task-number: QTBUG-42510 Task-number: QTBUG-37261 Change-Id: Ic11bec0a25e66df9d022f640621686be867e84d2 Reviewed-by: Gunnar Sletta --- src/gui/opengl/qopenglframebufferobject.cpp | 20 +++++++++++++++++--- src/opengl/qglframebufferobject.cpp | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index 83cfaf8f93..124d9d53f6 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -1203,9 +1203,23 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, If used together with QOpenGLPaintDevice, \a flipped should be the opposite of the value of QOpenGLPaintDevice::paintFlipped(). - Will try to return a premultiplied ARBG32 or RGB32 image. Since 5.2 it will fall back to - a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported. Since 5.4 an - A2BGR30 image is returned if the internal format is RGB10_A2. + The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used + only when internalTextureFormat() is set to \c GL_RGB. + + If the rendering in the framebuffer was not done with premultiplied alpha in mind, + create a wrapper QImage with a non-premultiplied format. This is necessary before + performing operations like QImage::save() because otherwise the image data would get + unpremultiplied, even though it was not premultiplied in the first place. To create + such a wrapper without performing a copy of the pixel data, do the following: + + \code + QImage fboImage(fbo.toImage()); + QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); + \endcode + + Since Qt 5.2 the function will fall back to premultiplied RGBA8888 or RGBx8888 when + reading to (A)RGB32 is not supported. Since 5.4 an A2BGR30 image is returned if the + internal format is RGB10_A2. For multisampled framebuffer objects the samples are resolved using the \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 49b28c36b9..4537f5bfae 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -1111,6 +1111,20 @@ QGLFramebufferObjectFormat QGLFramebufferObject::format() const Returns the contents of this framebuffer object as a QImage. + The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used + only when internalTextureFormat() is set to \c GL_RGB. + + If the rendering in the framebuffer was not done with premultiplied alpha in mind, + create a wrapper QImage with a non-premultiplied format. This is necessary before + performing operations like QImage::save() because otherwise the image data would get + unpremultiplied, even though it was not premultiplied in the first place. To create + such a wrapper without performing a copy of the pixel data, do the following: + + \code + QImage fboImage(fbo.toImage()); + QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); + \endcode + On QNX the back buffer is not preserved when a buffer swap occures. So this function might return old content. */ From 2fb3941198f43b653cb53f53b59830c9b9856835 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 30 Oct 2014 14:43:51 +0100 Subject: [PATCH 260/323] QPanGestureRecognizer: Make the number of touch points a parameter. Prepare for determining the suitable number of touch points from the device type. For now, 2 points are used as before, which can be overridden by setting the environment variable QT_PAN_TOUCHPOINTS. Add member variable to QPanGesturePrivate which is set on gesture creation and later used for comparison. Task-number: QTBUG-40461 Change-Id: I6d9e35ca752375bc6a54435482ca0925195b8142 Reviewed-by: Shawn Rutledge --- src/widgets/kernel/qgesture_p.h | 3 +- src/widgets/kernel/qgesturemanager.cpp | 20 +++++++++++- src/widgets/kernel/qstandardgestures.cpp | 32 +++++++++---------- src/widgets/kernel/qstandardgestures_p.h | 5 ++- .../tst_qgesturerecognizer.cpp | 1 + 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/widgets/kernel/qgesture_p.h b/src/widgets/kernel/qgesture_p.h index 183a2eba0f..26d9ede59d 100644 --- a/src/widgets/kernel/qgesture_p.h +++ b/src/widgets/kernel/qgesture_p.h @@ -80,7 +80,7 @@ class QPanGesturePrivate : public QGesturePrivate public: QPanGesturePrivate() - : acceleration(0), xVelocity(0), yVelocity(0) + : acceleration(0), xVelocity(0), yVelocity(0), pointCount(2) { } @@ -95,6 +95,7 @@ public: qreal acceleration; qreal xVelocity; qreal yVelocity; + int pointCount; // ### fixme Qt 5.5: Add accessor to QPanGesture. }; class QPinchGesturePrivate : public QGesturePrivate diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index 739e6b1870..c9af3062d3 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -63,6 +63,24 @@ QT_BEGIN_NAMESPACE +static inline int panTouchPoints() +{ + // Override by environment variable for testing. + static const char panTouchPointVariable[] = "QT_PAN_TOUCHPOINTS"; + if (qEnvironmentVariableIsSet(panTouchPointVariable)) { + bool ok; + const int result = qgetenv(panTouchPointVariable).toInt(&ok); + if (ok && result >= 1) + return result; + qWarning() << "Ignoring invalid value of " << panTouchPointVariable; + } + // Pan should use 1 finger on a touch screen and 2 fingers on touch pads etc. + // where 1 finger movements are used for mouse event synthetization. For now, + // default to 2 until all classes inheriting QScrollArea are fixed to handle it + // correctly. + return 2; +} + QGestureManager::QGestureManager(QObject *parent) : QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture) { @@ -73,7 +91,7 @@ QGestureManager::QGestureManager(QObject *parent) registerGestureRecognizer(new QMacPinchGestureRecognizer); registerGestureRecognizer(new QMacPanGestureRecognizer); #else - registerGestureRecognizer(new QPanGestureRecognizer); + registerGestureRecognizer(new QPanGestureRecognizer(panTouchPoints())); registerGestureRecognizer(new QPinchGestureRecognizer); registerGestureRecognizer(new QSwipeGestureRecognizer); registerGestureRecognizer(new QTapGestureRecognizer); diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index 9e3cb473e5..6656903e70 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -44,10 +44,6 @@ QT_BEGIN_NAMESPACE -QPanGestureRecognizer::QPanGestureRecognizer() -{ -} - QGesture *QPanGestureRecognizer::create(QObject *target) { if (target && target->isWidgetType()) { @@ -62,6 +58,15 @@ QGesture *QPanGestureRecognizer::create(QObject *target) return new QPanGesture; } +static QPointF panOffset(const QList &touchPoints, int maxCount) +{ + QPointF result; + const int count = qMin(touchPoints.size(), maxCount); + for (int p = 0; p < count; ++p) + result += touchPoints.at(p).pos() - touchPoints.at(p).startPos(); + return result / qreal(count); +} + QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, QObject *, QEvent *event) @@ -76,18 +81,15 @@ QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, result = QGestureRecognizer::MayBeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastOffset = d->offset = QPointF(); + d->pointCount = m_pointCount; break; } case QEvent::TouchEnd: { if (q->state() != Qt::NoGesture) { const QTouchEvent *ev = static_cast(event); - if (ev->touchPoints().size() == 2) { - QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); - QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + if (ev->touchPoints().size() == d->pointCount) { d->lastOffset = d->offset; - d->offset = - QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), - p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + d->offset = panOffset(ev->touchPoints(), d->pointCount); } result = QGestureRecognizer::FinishGesture; } else { @@ -97,16 +99,12 @@ QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, } case QEvent::TouchUpdate: { const QTouchEvent *ev = static_cast(event); - if (ev->touchPoints().size() >= 2) { - QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); - QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + if (ev->touchPoints().size() >= d->pointCount) { d->lastOffset = d->offset; - d->offset = - QPointF(p1.pos().x() - p1.startPos().x() + p2.pos().x() - p2.startPos().x(), - p1.pos().y() - p1.startPos().y() + p2.pos().y() - p2.startPos().y()) / 2; + d->offset = panOffset(ev->touchPoints(), d->pointCount); if (d->offset.x() > 10 || d->offset.y() > 10 || d->offset.x() < -10 || d->offset.y() < -10) { - q->setHotSpot(p1.startScreenPos()); + q->setHotSpot(ev->touchPoints().first().startScreenPos()); result = QGestureRecognizer::TriggerGesture; } else { result = QGestureRecognizer::MayBeGesture; diff --git a/src/widgets/kernel/qstandardgestures_p.h b/src/widgets/kernel/qstandardgestures_p.h index aeabd9cc7e..15ba31f26a 100644 --- a/src/widgets/kernel/qstandardgestures_p.h +++ b/src/widgets/kernel/qstandardgestures_p.h @@ -55,11 +55,14 @@ QT_BEGIN_NAMESPACE class QPanGestureRecognizer : public QGestureRecognizer { public: - QPanGestureRecognizer(); + explicit QPanGestureRecognizer(int pointCount = 2) : m_pointCount(pointCount) {} QGesture *create(QObject *target); QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); void reset(QGesture *state); + +private: + const int m_pointCount; }; class QPinchGestureRecognizer : public QGestureRecognizer diff --git a/tests/auto/widgets/gestures/qgesturerecognizer/tst_qgesturerecognizer.cpp b/tests/auto/widgets/gestures/qgesturerecognizer/tst_qgesturerecognizer.cpp index 833494f25e..bdf610e426 100644 --- a/tests/auto/widgets/gestures/qgesturerecognizer/tst_qgesturerecognizer.cpp +++ b/tests/auto/widgets/gestures/qgesturerecognizer/tst_qgesturerecognizer.cpp @@ -71,6 +71,7 @@ tst_QGestureRecognizer::tst_QGestureRecognizer() : m_fingerDistance(qRound(QGuiApplication::primaryScreen()->physicalDotsPerInch() / 2.0)) , m_touchDevice(new QTouchDevice) { + qputenv("QT_PAN_TOUCHPOINTS", "2"); // Prevent device detection of pan touch point count. } void tst_QGestureRecognizer::initTestCase() From b00d4475aafa31fef808c4b5839383b827273ddd Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 17 Nov 2014 10:13:14 +0100 Subject: [PATCH 261/323] Fix broken resource cleanup in QOpenGLWidget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The context has to be made current. Otherwise we may fail to clean up or, what's worse, we may delete FBOs and textures in some random context. The latter was visible with ANGLE in the qopenglwidget example. When having two QOpenGLWidget instances, the context for the second happened to be the current one when destroying the first. This is now avoided by making sure the correct context is current when deleting the FBOs. Task-number: QTBUG-42696 Change-Id: I8c1eed7c13a869968cc67141e585d02c6bc6f279 Reviewed-by: Friedemann Kleint Reviewed-by: Jørgen Lind --- src/widgets/kernel/qopenglwidget.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 8a4e0c8ffd..eee4aa546c 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -578,12 +578,22 @@ GLuint QOpenGLWidgetPrivate::textureId() const void QOpenGLWidgetPrivate::reset() { + Q_Q(QOpenGLWidget); + + // Destroy the OpenGL resources first. These need the context to be current. + if (initialized) + q->makeCurrent(); + delete paintDevice; paintDevice = 0; delete fbo; fbo = 0; delete resolvedFbo; resolvedFbo = 0; + + if (initialized) + q->doneCurrent(); + // Delete the context first, then the surface. Slots connected to // the context's aboutToBeDestroyed() may still call makeCurrent() // to perform some cleanup. From 24d06c8c3cdabb080f13940bd38e324659b402d0 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 17 Nov 2014 12:32:13 +0100 Subject: [PATCH 262/323] Fix missing docs for QByteArrayList The public is needed for qdoc which sees class, not struct. Task-number: QTBUG-42689 Change-Id: I28298b5fd13c6841838634a440bb2f726ddbe7be Reviewed-by: Olivier Goffart --- src/corelib/tools/qbytearraylist.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/tools/qbytearraylist.h b/src/corelib/tools/qbytearraylist.h index 9d7e776028..dd84ec642c 100644 --- a/src/corelib/tools/qbytearraylist.h +++ b/src/corelib/tools/qbytearraylist.h @@ -63,6 +63,7 @@ class QByteArrayList : public QList template <> struct QListSpecialMethods #endif { +public: inline QByteArray join() const { return QtPrivate::QByteArrayList_join(self(), 0, 0); } inline QByteArray join(const QByteArray &sep) const From 32bc5f01c416a4a54fd0ff3835bd5d500707bce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 14 Nov 2014 17:03:57 +0100 Subject: [PATCH 263/323] Revert "Build Qt for OS X and iOS with relative rpath" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The change was made too late in the 5.4.0 release cycle, and broke the Qt build and deployment in several areas: - macdeployqt - OS X 10.7 builds - shadow builds This reverts commit c0a54efc4091b365ffac09fc2827cf92f849d698. Change-Id: I1c1ad4901228f5516352ccdfa963e8ea2b5013b6 Reviewed-by: Morten Johan Sørvig Reviewed-by: Gabriel de Dietrich --- configure | 6 +++++- mkspecs/features/qt_build_config.prf | 6 ++++++ mkspecs/features/qt_module.prf | 3 --- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 979e32e050..1a002b4081 100755 --- a/configure +++ b/configure @@ -5784,7 +5784,11 @@ fi [ '!' -z "$INCLUDES" ] && QMakeVar add INCLUDEPATH "$INCLUDES" [ '!' -z "$L_FLAGS" ] && QMakeVar add LIBS "$L_FLAGS" -if [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then +if [ "$XPLATFORM_MAC" = "yes" ] && [ "$QT_CROSS_COMPILE" = "no" ]; then + if [ "$CFG_RPATH" = "yes" ]; then + QMAKE_CONFIG="$QMAKE_CONFIG absolute_library_soname" + fi +elif [ -z "`getXQMakeConf 'QMAKE_(LFLAGS_)?RPATH'`" ]; then if [ -n "$RPATH_FLAGS" ]; then echo echo "ERROR: -R cannot be used on this platform as \$QMAKE_LFLAGS_RPATH is" diff --git a/mkspecs/features/qt_build_config.prf b/mkspecs/features/qt_build_config.prf index 7197f84c9a..42046c238a 100644 --- a/mkspecs/features/qt_build_config.prf +++ b/mkspecs/features/qt_build_config.prf @@ -52,6 +52,12 @@ QMAKE_DIR_REPLACE_SANE = PRECOMPILED_DIR OBJECTS_DIR MOC_DIR RCC_DIR UI_DIR unset(modpath) } +mac { + !isEmpty(QMAKE_RPATHDIR){ + CONFIG += absolute_library_soname + } +} + cross_compile: \ CONFIG += force_bootstrap diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 7d47caef46..8599a47ecd 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -111,9 +111,6 @@ mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { } } -mac:contains(QT_CONFIG, rpath): \ - QMAKE_SONAME_PREFIX = @rpath - mac { CONFIG += explicitlib macx-g++ { From e4d9102805e2e733d00a3de926ef97337e6d58cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 13 Nov 2014 14:20:32 +0100 Subject: [PATCH 264/323] Set CFBundleIdentifier prefix for Qt frameworks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sets the prefix for frameworks to "org.qt-project". Applications keep using the default Xcode preferences prefix. Task-number: QTBUG-32896 Change-Id: I67384f643888f2de3dd8e36b9bce0f04ca4e16dd Reviewed-by: Tor Arne Vestbø --- mkspecs/features/qt_module.prf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 8599a47ecd..d213f9e260 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -94,6 +94,8 @@ else: \ # OS X and iOS frameworks mac:CONFIG(shared, static|shared):contains(QT_CONFIG, qt_framework) { + # Set the CFBundleIdentifier prefix for Qt frameworks + QMAKE_TARGET_BUNDLE_PREFIX = org.qt-project #QMAKE_FRAMEWORK_VERSION = 4.0 CONFIG += lib_bundle sliced_bundle qt_framework CONFIG -= qt_install_headers #no need to install these as well From 40a4e446f37ee49783227d80fa1d805c8cab2463 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Mon, 17 Nov 2014 15:10:10 +0100 Subject: [PATCH 265/323] ANGLE: Fix compilation with D3D9 Fixes a regression introduced in c6df5fe3ed0f2a722 that broke compilation with d3d9 (namely, -target xp). Task-number: QTBUG-42714 Change-Id: I1a5e9682d5463bfa082a5d0c062399a131a7cf52 Reviewed-by: Friedemann Kleint --- src/3rdparty/angle/src/common/NativeWindow.h | 7 ++- src/3rdparty/angle/src/common/platform.h | 1 + .../angle/src/common/win32/NativeWindow.cpp | 2 +- ...0017-ANGLE-Fix-compilation-with-D3D9.patch | 62 +++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h index 9e93aeacde..c4a0e42bcc 100644 --- a/src/3rdparty/angle/src/common/NativeWindow.h +++ b/src/3rdparty/angle/src/common/NativeWindow.h @@ -54,7 +54,12 @@ public: bool getClientRect(LPRECT rect); bool isIconic(); - HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, +# if defined(ANGLE_ENABLE_D3D11) + typedef ID3D11Device Device; +#else + typedef IDirect3DDevice9 Device; +#endif + HRESULT createSwapChain(Device* device, DXGIFactory* factory, DXGI_FORMAT format, UINT width, UINT height, DXGISwapChain** swapChain); diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h index 0001e7142e..5bf97f9184 100644 --- a/src/3rdparty/angle/src/common/platform.h +++ b/src/3rdparty/angle/src/common/platform.h @@ -52,6 +52,7 @@ # if defined(ANGLE_ENABLE_D3D9) # include +# include # if !defined(COMPILER_IMPLEMENTATION) # include # endif diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp index 2440747260..46082a2e28 100644 --- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp @@ -35,7 +35,7 @@ bool NativeWindow::isIconic() return IsIconic(mWindow) == TRUE; } -HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, +HRESULT NativeWindow::createSwapChain(NativeWindow::Device* device, DXGIFactory* factory, DXGI_FORMAT format, unsigned int width, unsigned int height, DXGISwapChain** swapChain) { diff --git a/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch b/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch new file mode 100644 index 0000000000..4ada6d41d2 --- /dev/null +++ b/src/angle/patches/0017-ANGLE-Fix-compilation-with-D3D9.patch @@ -0,0 +1,62 @@ +From d7839cc052de126cc3b457fe41963fd9c7e91846 Mon Sep 17 00:00:00 2001 +From: Kai Koehne +Date: Mon, 17 Nov 2014 15:10:10 +0100 +Subject: [PATCH] ANGLE: Fix compilation with D3D9 + +Fixes a regression introduced in c6df5fe3ed0f2a722 that +broke compilation with d3d9 (namely, -target xp). + +Task-number: QTBUG-42714 +Change-Id: I1a5e9682d5463bfa082a5d0c062399a131a7cf52 +--- + src/3rdparty/angle/src/common/NativeWindow.h | 7 ++++++- + src/3rdparty/angle/src/common/platform.h | 1 + + src/3rdparty/angle/src/common/win32/NativeWindow.cpp | 2 +- + 3 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/3rdparty/angle/src/common/NativeWindow.h b/src/3rdparty/angle/src/common/NativeWindow.h +index 9e93aea..c4a0e42 100644 +--- a/src/3rdparty/angle/src/common/NativeWindow.h ++++ b/src/3rdparty/angle/src/common/NativeWindow.h +@@ -54,7 +54,12 @@ public: + bool getClientRect(LPRECT rect); + bool isIconic(); + +- HRESULT createSwapChain(ID3D11Device* device, DXGIFactory* factory, ++# if defined(ANGLE_ENABLE_D3D11) ++ typedef ID3D11Device Device; ++#else ++ typedef IDirect3DDevice9 Device; ++#endif ++ HRESULT createSwapChain(Device* device, DXGIFactory* factory, + DXGI_FORMAT format, UINT width, UINT height, + DXGISwapChain** swapChain); + +diff --git a/src/3rdparty/angle/src/common/platform.h b/src/3rdparty/angle/src/common/platform.h +index 0001e71..5bf97f9 100644 +--- a/src/3rdparty/angle/src/common/platform.h ++++ b/src/3rdparty/angle/src/common/platform.h +@@ -52,6 +52,7 @@ + + # if defined(ANGLE_ENABLE_D3D9) + # include ++# include + # if !defined(COMPILER_IMPLEMENTATION) + # include + # endif +diff --git a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +index 2440747..46082a2 100644 +--- a/src/3rdparty/angle/src/common/win32/NativeWindow.cpp ++++ b/src/3rdparty/angle/src/common/win32/NativeWindow.cpp +@@ -35,7 +35,7 @@ bool NativeWindow::isIconic() + return IsIconic(mWindow) == TRUE; + } + +-HRESULT NativeWindow::createSwapChain(ID3D11Device* device, DXGIFactory* factory, ++HRESULT NativeWindow::createSwapChain(NativeWindow::Device* device, DXGIFactory* factory, + DXGI_FORMAT format, unsigned int width, unsigned int height, + DXGISwapChain** swapChain) + { +-- +1.9.4.msysgit.0 + From 8aa2ae3e0e1f07c7dbb43790e35d9c87ec148bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 17 Nov 2014 15:00:45 +0100 Subject: [PATCH 266/323] iOS: Tell Xcode to not build universal app binaries for debug builds You're likely to only target/develop on one device at a time, so we only need to build for one architecture at a time. Switching device in Xcode will switch the active architecture as well, so the only case where you'll need a universal debug build is if you are creating a debug package for testers. Change-Id: I4f37f5c982082c42836749d1e9fbe5ef91138912 Reviewed-by: Oswald Buddenhagen Reviewed-by: Richard Moe Gustavsen --- mkspecs/macx-ios-clang/features/default_post.prf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mkspecs/macx-ios-clang/features/default_post.prf b/mkspecs/macx-ios-clang/features/default_post.prf index 0245c948d9..643a17e23e 100644 --- a/mkspecs/macx-ios-clang/features/default_post.prf +++ b/mkspecs/macx-ios-clang/features/default_post.prf @@ -202,6 +202,11 @@ macx-xcode { QMAKE_MAC_XCODE_SETTINGS += arch_iphoneos arch_iphonesimulator QMAKE_XCODE_ARCHS = $$QMAKE_IOS_DEVICE_ARCHS $$QMAKE_IOS_SIMULATOR_ARCHS + + only_active_arch.name = ONLY_ACTIVE_ARCH + only_active_arch.value = YES + only_active_arch.build = debug + QMAKE_MAC_XCODE_SETTINGS += only_active_arch } else { # Be more specific about which architecture we're targeting contains(QT_ARCH, arm.*): \ From 41f8d1f393f049f31648bd9fa7eb7ad357fe2d7b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 17 Nov 2014 13:43:24 +0100 Subject: [PATCH 267/323] Fix wrong qversionnumber header name in tools.pri Change-Id: Ie571ca0dc1720bcd04e492697e93f866b1877a5b Reviewed-by: Keith Gardner Reviewed-by: Oswald Buddenhagen --- src/corelib/tools/tools.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index af0ed228bd..cef802fa76 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -71,7 +71,7 @@ HEADERS += \ tools/qunicodetools_p.h \ tools/qvarlengtharray.h \ tools/qvector.h \ - tools/qversionnumber.h + tools/qversionnumber_p.h SOURCES += \ From 6f66205bacec923d989fa129796d5bd7e3786e4d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Nov 2014 11:48:08 +0100 Subject: [PATCH 268/323] Add Windows-specific notation for WebDAV to QUrl. Convert a Windows-specific WebDAV specification "//host@SSL/path" into URL's with scheme set to "webdavs" and back to local file (Windows only). Task-number: QTBUG-42346 Change-Id: I12663243848ea7b2d3f208743e837e9de14a93eb Reviewed-by: David Faure Reviewed-by: Thiago Macieira --- src/corelib/io/qurl.cpp | 41 +++++++++++++++++++++---- tests/auto/corelib/io/qurl/tst_qurl.cpp | 9 ++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index d4c5e03058..686050fa49 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -429,6 +429,16 @@ static inline QString fileScheme() return QStringLiteral("file"); } +static inline QString webDavScheme() +{ + return QStringLiteral("webdavs"); +} + +static inline QString webDavSslTag() +{ + return QStringLiteral("@SSL"); +} + #ifdef Q_COMPILER_CLASS_ENUM # define colon_uchar : uchar #else @@ -992,10 +1002,15 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro } // did we set to the file protocol? - if (scheme == fileScheme()) + if (scheme == fileScheme() +#ifdef Q_OS_WIN + || scheme == webDavScheme() +#endif + ) { flags |= IsLocalFile; - else + } else { flags &= ~IsLocalFile; + } return true; } @@ -3738,7 +3753,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile) QUrl url; if (localFile.isEmpty()) return url; - url.setScheme(fileScheme()); + QString scheme = fileScheme(); QString deslashified = QDir::fromNativeSeparators(localFile); // magic for drives on windows @@ -3747,13 +3762,21 @@ QUrl QUrl::fromLocalFile(const QString &localFile) } else if (deslashified.startsWith(QLatin1String("//"))) { // magic for shared drive on windows int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2); - url.setHost(deslashified.mid(2, indexOfPath - 2)); + QString hostSpec = deslashified.mid(2, indexOfPath - 2); + // Check for Windows-specific WebDAV specification: "//host@SSL/path". + if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) { + hostSpec.chop(4); + scheme = webDavScheme(); + } + url.setHost(hostSpec); + if (indexOfPath > 2) deslashified = deslashified.right(deslashified.length() - indexOfPath); else deslashified.clear(); } + url.setScheme(scheme); url.setPath(deslashified, DecodedMode); return url; } @@ -3783,8 +3806,14 @@ QString QUrl::toLocalFile() const // magic for shared drive on windows if (!d->host.isEmpty()) { - tmp = QStringLiteral("//") + host() + (ourPath.length() > 0 && ourPath.at(0) != QLatin1Char('/') - ? QLatin1Char('/') + ourPath : ourPath); + tmp = QStringLiteral("//") + host(); +#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. + if (scheme() == webDavScheme()) + tmp += webDavSslTag(); +#endif + if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/'))) + tmp += QLatin1Char('/'); + tmp += ourPath; } else { tmp = ourPath; #ifdef Q_OS_WIN diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 5b5161e24a..6d801f75c1 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -1179,6 +1179,12 @@ void tst_QUrl::toLocalFile_data() QTest::newRow("data0") << QString::fromLatin1("file:/a.txt") << QString::fromLatin1("/a.txt"); QTest::newRow("data4") << QString::fromLatin1("file:///a.txt") << QString::fromLatin1("/a.txt"); + QTest::newRow("data4a") << QString::fromLatin1("webdavs://somewebdavhost/somedir/somefile") +#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. + << QString::fromLatin1("//somewebdavhost@SSL/somedir/somefile"); +#else + << QString(); +#endif #ifdef Q_OS_WIN QTest::newRow("data5") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("c:/a.txt"); #else @@ -1227,6 +1233,9 @@ void tst_QUrl::fromLocalFile_data() QTest::newRow("data3") << QString::fromLatin1("c:/a.txt") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("/c:/a.txt"); QTest::newRow("data4") << QString::fromLatin1("//somehost/somedir/somefile") << QString::fromLatin1("file://somehost/somedir/somefile") << QString::fromLatin1("/somedir/somefile"); + QTest::newRow("data4a") << QString::fromLatin1("//somewebdavhost@SSL/somedir/somefile") + << QString::fromLatin1("webdavs://somewebdavhost/somedir/somefile") + << QString::fromLatin1("/somedir/somefile"); QTest::newRow("data5") << QString::fromLatin1("//somehost") << QString::fromLatin1("file://somehost") << QString::fromLatin1(""); QTest::newRow("data6") << QString::fromLatin1("//somehost/") << QString::fromLatin1("file://somehost/") From e37a69252eb7c564fd888361b3672cfc31eca949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Mon, 17 Nov 2014 18:41:05 +0100 Subject: [PATCH 269/323] Fix memcpy with incorrect destination Variable dsa is assigned in this block with q_DSA_new instead of rsa. So this should be the destination of memcpy. Change-Id: Id5a41d99f1606bf525ad5f819bbc06bb1235bf5b Reviewed-by: Richard J. Moore --- src/network/ssl/qsslkey_openssl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp index 6b0fa954eb..e4d30ff229 100644 --- a/src/network/ssl/qsslkey_openssl.cpp +++ b/src/network/ssl/qsslkey_openssl.cpp @@ -95,7 +95,7 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey) type = QSsl::PrivateKey; dsa = q_DSA_new(); - memcpy(rsa, q_EVP_PKEY_get1_DSA(pkey), sizeof(DSA)); + memcpy(dsa, q_EVP_PKEY_get1_DSA(pkey), sizeof(DSA)); return true; } From 87636ec58251b568a09695ab5bb7e44ecb296a28 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 17 Nov 2014 15:37:21 +0100 Subject: [PATCH 270/323] Save a detach if QBrush::setColor does not change the brush color MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can save detaching a QBrush when setColor is called trying to set the current color. Change-Id: I8f4042325d0f9c2bda69d469d6861e3cc310f329 Reviewed-by: Samuel Rødal --- src/gui/painting/qbrush.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index d120175108..d136f3a903 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -708,6 +708,9 @@ void QBrush::setStyle(Qt::BrushStyle style) void QBrush::setColor(const QColor &c) { + if (d->color == c) + return; + detach(d->style); d->color = c; } From e86f1ceaedba24187747ab6b1d4b4712fbcca137 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 13 Nov 2014 15:23:27 +0100 Subject: [PATCH 271/323] qdoc: Missing break in qdoc switch statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a missing break statement in the function that generates the .index file, which caused qdoc to output extra attributes in the element. Change-Id: I110c15c67a228249bfe0c7da138f2ca0b4921371 Task-number: QTBUG-42625 Reviewed-by: Topi Reiniö --- src/tools/qdoc/qdocindexfiles.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 7445292a56..00041b2b65 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -980,6 +980,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } + break; case Node::QmlModule: { const QmlModuleNode* qmn = static_cast(node); From 9990e47f047925fce978ebda849bd7ae88608003 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 7 Nov 2014 15:14:13 -0800 Subject: [PATCH 272/323] Fix build Caused by qstringlist.h no longer including qdatastream.h. Change-Id: I4dee5565ebaa1c8593633a6ad27f142e4424c5c9 Reviewed-by: David Faure --- src/corelib/io/qurl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 686050fa49..b21e9b51e1 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -403,6 +403,7 @@ #include "qdebug.h" #include "qhash.h" #include "qdir.h" // for QDir::fromNativeSeparators +#include "qdatastream.h" #include "qtldurl_p.h" #include "private/qipaddress_p.h" #include "qurlquery.h" From ccd4da392c366dd4f7f71fa3b8aeddde1b3bc169 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 12 Nov 2014 16:58:15 +0100 Subject: [PATCH 273/323] Do not force a content-type on POST request with no content While a POST request with no body may be a pointless thing it does happen on many websites. Currently this causes QtNetwork to print a warning to the console and set an invalid content-type. This patch allows the content-type to be absent when content is. Task-number: QTBUG-42479 Change-Id: Ia84c89147d2469a9421b9694d062c797987b3194 Reviewed-by: Jocelyn Turcotte Reviewed-by: Thiago Macieira --- src/network/access/qhttpnetworkrequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index f50a79b061..66f093e490 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -151,7 +151,7 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request } if (request.d->operation == QHttpNetworkRequest::Post) { // add content type, if not set in the request - if (request.headerField("content-type").isEmpty()) { + if (request.headerField("content-type").isEmpty() && ((request.d->uploadByteDevice && request.d->uploadByteDevice->size() > 0) || request.d->url.hasQuery())) { //Content-Type is mandatory. We can't say anything about the encoding, but x-www-form-urlencoded is the most likely to work. //This warning indicates a bug in application code not setting a required header. //Note that if using QHttpMultipart, the content-type is set in QNetworkAccessManagerPrivate::prepareMultipart already From c2c48b3ea9e1b6c7b3eb7d7a5b660bce8e6ff4ca Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 19 Nov 2014 09:21:25 +0100 Subject: [PATCH 274/323] Add a note about group separators to numeric validators. Task-number: QTBUG-42522 Change-Id: I202cb98c51ba2332000772edfdc47d47c56e49c9 Reviewed-by: Mitch Curtis --- src/gui/util/qvalidator.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 1b5a10f733..93990a8748 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -316,7 +316,12 @@ void QValidator::fixup(QString &) const QIntValidator uses its locale() to interpret the number. For example, in Arabic locales, QIntValidator will accept Arabic digits. - \sa QDoubleValidator, QRegExpValidator, {Line Edits Example} + \note The QLocale::NumberOptions set on the locale() also affect the + way the number is interpreted. For example, since QLocale::RejectGroupSeparator + is not set by default, the validator will accept group separators. It is thus + recommended to use QLocale::toInt() to obtain the numeric value. + + \sa QDoubleValidator, QRegExpValidator, QLocale::toInt(), {Line Edits Example} */ /*! @@ -548,7 +553,12 @@ public: in the German locale, "1,234" will be accepted as the fractional number 1.234. In Arabic locales, QDoubleValidator will accept Arabic digits. - \sa QIntValidator, QRegExpValidator, {Line Edits Example} + \note The QLocale::NumberOptions set on the locale() also affect the + way the number is interpreted. For example, since QLocale::RejectGroupSeparator + is not set by default, the validator will accept group separators. It is thus + recommended to use QLocale::toDouble() to obtain the numeric value. + + \sa QIntValidator, QRegExpValidator, QLocale::toDouble(), {Line Edits Example} */ /*! From 85a4aaa5ce7caa783a187b775961db3a77a3afb6 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Tue, 11 Nov 2014 13:38:05 +0100 Subject: [PATCH 275/323] Fix invalid qmake syntax Task-number: QTBUG-42549 Change-Id: I57ba3150e3a3b915faf0356d8a3f89801eb4963e Reviewed-by: Oswald Buddenhagen Reviewed-by: Timur Pocheptsov Reviewed-by: Frederik Gladhorn --- tests/auto/network/ssl/ssl.pro | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/auto/network/ssl/ssl.pro b/tests/auto/network/ssl/ssl.pro index 0cf910df73..4e30a9cded 100644 --- a/tests/auto/network/ssl/ssl.pro +++ b/tests/auto/network/ssl/ssl.pro @@ -5,19 +5,21 @@ SUBDIRS=\ qsslerror \ qsslkey \ -contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked): +contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { contains(QT_CONFIG, private_tests) { SUBDIRS += \ qsslsocket \ qsslsocket_onDemandCertificates_member \ qsslsocket_onDemandCertificates_static \ } +} winrt: SUBDIRS -= \ qsslsocket_onDemandCertificates_member \ qsslsocket_onDemandCertificates_static \ -contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked): +contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { contains(QT_CONFIG, private_tests) { - SUBDIRS += qasn1element + SUBDIRS += qasn1element + } } From 42b4dda39ccedc60dccddc345ea813168b13df40 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Thu, 13 Nov 2014 13:52:05 +0100 Subject: [PATCH 276/323] Fix rubberband position for tabbed mdi windows Place the rubberband over the tabs instead of where the hidden subwindows happen to be. [ChangeLog][QtWidgets][QMdiArea] Fix rubberband position for tabbed mdi windows Task-number: QTBUG-42612 Change-Id: I41e81ab8b99ab9e0fa533fd4ed1b2a8141d19753 Reviewed-by: Friedemann Kleint --- src/widgets/widgets/qmdiarea.cpp | 16 +++++++++++++++- src/widgets/widgets/qmdiarea_p.h | 9 +-------- .../widgets/widgets/qmdiarea/tst_qmdiarea.cpp | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp index 1e291f469e..3553baf68a 100644 --- a/src/widgets/widgets/qmdiarea.cpp +++ b/src/widgets/widgets/qmdiarea.cpp @@ -1511,7 +1511,7 @@ void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor) #ifndef QT_NO_RUBBERBAND if (!rubberBand) { - rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport); + rubberBand = new QRubberBand(QRubberBand::Rectangle, q); // For accessibility to identify this special widget. rubberBand->setObjectName(QLatin1String("qt_rubberband")); rubberBand->setWindowFlags(rubberBand->windowFlags() | Qt::WindowStaysOnTopHint); @@ -1528,6 +1528,20 @@ void QMdiAreaPrivate::highlightNextSubWindow(int increaseFactor) Q_ASSERT(indexToHighlighted >= 0); } +void QMdiAreaPrivate::showRubberBandFor(QMdiSubWindow *subWindow) +{ + if (!subWindow || !rubberBand) + return; + + if (viewMode == QMdiArea::TabbedView) + rubberBand->setGeometry(tabBar->tabRect(childWindows.indexOf(subWindow))); + else + rubberBand->setGeometry(subWindow->geometry()); + + rubberBand->raise(); + rubberBand->show(); +} + /*! \internal \since 4.4 diff --git a/src/widgets/widgets/qmdiarea_p.h b/src/widgets/widgets/qmdiarea_p.h index 1092fd9a30..ba531adaad 100644 --- a/src/widgets/widgets/qmdiarea_p.h +++ b/src/widgets/widgets/qmdiarea_p.h @@ -248,14 +248,7 @@ public: } #ifndef QT_NO_RUBBERBAND - inline void showRubberBandFor(QMdiSubWindow *subWindow) - { - if (!subWindow || !rubberBand) - return; - rubberBand->setGeometry(subWindow->geometry()); - rubberBand->raise(); - rubberBand->show(); - } + void showRubberBandFor(QMdiSubWindow *subWindow); inline void hideRubberBand() { diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp index f457955657..ff9bc7c4a2 100644 --- a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp +++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp @@ -104,7 +104,7 @@ static bool tabBetweenSubWindowsIn(QMdiArea *mdiArea, int tabCount = -1, bool re if (tabCount > 1) QTest::qWait(500); if (walkThrough) { - QRubberBand *rubberBand = mdiArea->viewport()->findChild(); + QRubberBand *rubberBand = mdiArea->findChild(); if (!rubberBand) { qWarning("No rubber band"); return false; From a1d61e70ca5db4a3c7e0008b0175197327c5d6b4 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 24 Oct 2014 14:45:08 +0200 Subject: [PATCH 277/323] Doc: added NoGesture to GestureState enum Task-number: QTBUG-39988 Change-Id: I5481dfec75c90267a3a9be0d212df7384016e69d Reviewed-by: Martin Smith --- src/corelib/global/qnamespace.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 4e074bcdb5..28d26f848d 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2803,11 +2803,11 @@ This enum type describes the state of a gesture. + \value NoGesture No gesture has been detected. \value GestureStarted A continuous gesture has started. \value GestureUpdated A gesture continues. \value GestureFinished A gesture has finished. \value GestureCanceled A gesture was canceled. - \omitvalue NoGesture \sa QGesture */ From 6dac557fd3b9c913f1bc8b863bb676fc46df4b05 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 19 Nov 2014 12:05:27 +0100 Subject: [PATCH 278/323] Correct the signature and access rights for the protected constructor Change-Id: Ic43398a82777f3b1a95a36f60ebc4338d60c29ec Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglpaintdevice.cpp | 4 ++-- src/gui/opengl/qopenglpaintdevice.h | 2 +- src/widgets/kernel/qopenglwidget.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp index e908fd8e91..a08d26f708 100644 --- a/src/gui/opengl/qopenglpaintdevice.cpp +++ b/src/gui/opengl/qopenglpaintdevice.cpp @@ -138,8 +138,8 @@ QOpenGLPaintDevice::QOpenGLPaintDevice(int width, int height) /*! \internal */ -QOpenGLPaintDevice::QOpenGLPaintDevice(QOpenGLPaintDevicePrivate *dd) - : d_ptr(dd) +QOpenGLPaintDevice::QOpenGLPaintDevice(QOpenGLPaintDevicePrivate &dd) + : d_ptr(&dd) { } diff --git a/src/gui/opengl/qopenglpaintdevice.h b/src/gui/opengl/qopenglpaintdevice.h index dda3bfe43f..10cee842ab 100644 --- a/src/gui/opengl/qopenglpaintdevice.h +++ b/src/gui/opengl/qopenglpaintdevice.h @@ -53,7 +53,6 @@ public: QOpenGLPaintDevice(); explicit QOpenGLPaintDevice(const QSize &size); QOpenGLPaintDevice(int width, int height); - QOpenGLPaintDevice(QOpenGLPaintDevicePrivate *dd); virtual ~QOpenGLPaintDevice(); int devType() const { return QInternal::OpenGL; } @@ -76,6 +75,7 @@ public: virtual void ensureActiveTarget(); protected: + QOpenGLPaintDevice(QOpenGLPaintDevicePrivate &dd); int metric(QPaintDevice::PaintDeviceMetric metric) const; Q_DISABLE_COPY(QOpenGLPaintDevice) diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 8a4e0c8ffd..23bb1f7050 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -471,7 +471,7 @@ class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice { public: QOpenGLWidgetPaintDevice(QOpenGLWidget *widget) - : QOpenGLPaintDevice(new QOpenGLWidgetPaintDevicePrivate(widget)) { } + : QOpenGLPaintDevice(*new QOpenGLWidgetPaintDevicePrivate(widget)) { } void ensureActiveTarget() Q_DECL_OVERRIDE; }; From 242f1c2d63dd5f3381f13d46bdb08ccaba18ac1f Mon Sep 17 00:00:00 2001 From: Alex Blasche Date: Tue, 18 Nov 2014 15:18:05 +0100 Subject: [PATCH 279/323] Fix QtCreator debugging on Android 5.0 devices Add a socket based handshake method for gdb. The previous file based method remains for now and can be activated from Qt creator. It will be used by older creator builds but has the limitation of not working on 5.0 devices. The new mechanism works on pre 5.0 devices too. Task-number: QTCREATORBUG-13418 Change-Id: Ia3ecd1b144b544f52d90940ca885653bcbc477ac Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/QtActivityDelegate.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index cab5da9dbc..12b606b89f 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -72,10 +72,16 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import java.io.BufferedReader; +import java.io.DataOutputStream; import java.io.File; import java.io.FileWriter; +import java.io.InputStreamReader; import java.io.IOException; import java.lang.reflect.Method; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -488,6 +494,53 @@ public class QtActivityDelegate Log.i(QtNative.QtTAG, "DEBUGGER: " + msg); } + private class DebugWaitRunnable implements Runnable { + + public DebugWaitRunnable(int socketPort) throws IOException { + socket = new ServerSocket(socketPort); + } + + public boolean wasFailure; + private ServerSocket socket; + + public void run() { + final int napTime = 200; // milliseconds between file accesses + final int timeOut = 30000; // ms until we give up on ping and pong + final int maxAttempts = timeOut / napTime; + + try { + socket.setSoTimeout(timeOut); + debugLog("Waiting for debug socket on port: " + socket.getLocalPort()); + Socket connectionFromClient = socket.accept(); + debugLog("Debug socket accepted"); + BufferedReader inFromClient = + new BufferedReader(new InputStreamReader(connectionFromClient.getInputStream())); + DataOutputStream outToClient = new DataOutputStream(connectionFromClient.getOutputStream()); + outToClient.writeBytes("" + android.os.Process.myPid()); + + for (int i = 0; i < maxAttempts; i++) { + String clientData = inFromClient.readLine(); + debugLog("Incoming socket " + clientData); + if (!clientData.isEmpty()) + break; + + if (socket.isClosed()) { + wasFailure = true; + break; + } + Thread.sleep(napTime); + } + } catch (IOException ioEx) { + ioEx.printStackTrace(); + wasFailure = true; + Log.e(QtNative.QtTAG,"Can't start debugger" + ioEx.getMessage()); + } catch (InterruptedException interruptEx) { + wasFailure = true; + Log.e(QtNative.QtTAG,"Can't start debugger" + interruptEx.getMessage()); + } + } + }; + public boolean startApplication() { // start application @@ -544,9 +597,17 @@ public class QtActivityDelegate String pongFile = extras.getString("pong_file"); String gdbserverSocket = extras.getString("gdbserver_socket"); String gdbserverCommand = extras.getString("gdbserver_command"); + String pingViaSocket = extras.getString("ping_socketport"); boolean usePing = pingFile != null; boolean usePong = pongFile != null; boolean useSocket = gdbserverSocket != null; + int pingSocket = 0; + if (pingViaSocket != null) { + try { + pingSocket = Integer.parseInt(pingViaSocket); + } catch (NumberFormatException ignored) { } + } + boolean usePingViaSocket = (pingViaSocket != null && pingSocket > 0); int napTime = 200; // milliseconds between file accesses int timeOut = 30000; // ms until we give up on ping and pong int maxAttempts = timeOut / napTime; @@ -602,6 +663,20 @@ public class QtActivityDelegate debugLog("socket not used"); } + if (usePingViaSocket) { + DebugWaitRunnable runnable = new DebugWaitRunnable(pingSocket); + Thread waitThread = new Thread(runnable); + waitThread.start(); + waitThread.join(); + + if (runnable.wasFailure) { + debugLog("Could not connect to debug client"); + return false; + } else { + debugLog("Got pid acknowledgment"); + } + } + if (usePing) { // Tell we are ready. debugLog("writing ping at " + pingFile); From 52ea96db06d5ecb070dfd1e4fcf30c0c186ec906 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 18 Nov 2014 15:53:18 +0100 Subject: [PATCH 280/323] Doc: Added brief statement to group definition Groups: richtext and sharing. Task-number: QTBUG-42682 Change-Id: I46bd7e5bba0f665519ee4f3c033b971f0836e314 Reviewed-by: Martin Smith --- src/corelib/doc/src/implicit-sharing.qdoc | 1 + src/corelib/doc/src/statemachine.qdoc | 1 + src/gui/doc/src/richtext.qdoc | 1 + 3 files changed, 3 insertions(+) diff --git a/src/corelib/doc/src/implicit-sharing.qdoc b/src/corelib/doc/src/implicit-sharing.qdoc index 1185fe8348..ec8edb4b6b 100644 --- a/src/corelib/doc/src/implicit-sharing.qdoc +++ b/src/corelib/doc/src/implicit-sharing.qdoc @@ -30,6 +30,7 @@ /*! \group shared + \brief How to maximize resource usage by implicit data sharing. \title Implicitly Shared Classes These \l{Qt Core} classes provides a safe and efficient way of sharing and diff --git a/src/corelib/doc/src/statemachine.qdoc b/src/corelib/doc/src/statemachine.qdoc index b281eb177b..846eb7d1f0 100644 --- a/src/corelib/doc/src/statemachine.qdoc +++ b/src/corelib/doc/src/statemachine.qdoc @@ -27,6 +27,7 @@ /*! \group statemachine + \brief How to create and execute state graphs. \title State Machine Classes These \l{Qt Core} classes are part of the \l{The State Machine Framework}{ diff --git a/src/gui/doc/src/richtext.qdoc b/src/gui/doc/src/richtext.qdoc index 90248298d6..460018a52e 100644 --- a/src/gui/doc/src/richtext.qdoc +++ b/src/gui/doc/src/richtext.qdoc @@ -27,6 +27,7 @@ /*! \group richtext-processing + \brief How to use Rich Text Processing APIs. \title Rich Text Processing APIs */ From efeb15f3065ab01a3eed483385fa0421f617eb10 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 17 Nov 2014 15:01:35 +0100 Subject: [PATCH 281/323] add buildsystem changelog for 5.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I22ac7dc475fccb3c71e3f514fb58045062a1a95b Reviewed-by: Tor Arne Vestbø Reviewed-by: Thiago Macieira --- dist/changes-5.4.0 | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dist/changes-5.4.0 b/dist/changes-5.4.0 index 927ca0f9f1..614f57afe2 100644 --- a/dist/changes-5.4.0 +++ b/dist/changes-5.4.0 @@ -43,3 +43,46 @@ OS X - OS X 10.10 is now supported. - QMacStyle has been updated with better OS 10.10 support. - The Qt binary packages are now configured with C++11 enabled. + +Windows +------- + + - [QTBUG-38259] Changed configure defaults so that Qt5Core does not + link against ICU libraries anymore. Pass '-icu' to enable it. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - The -process/-fully-process/-dont-process configure options have been + removed due to being unnecessary and counterproductive. + - [QTBUG-36955] The -vcproj configure option was removed. Use "qmake -r -tp vc" + _after_ building Qt in case you want to use Visual Studio to work on Qt. + - [QTBUG-37961] Qt plugins contain version info again. + - [QTBUG-39216] Fixed more cases where the Qt build would pick up headers + from a pre-existing Qt installation. + - [QTBUG-41267] Fixed parallelized (jom) -debug-and-release builds. + +qmake +----- + + - [QTBUG-21910][Unix] Added 'make dist' target for SUBDIRS projects. + - [QTBUG-32895][iOS] Fixed structure of bundles. They can be signed now. + - [QTBUG-26782][VS] Fixed handling of TARGET_EXT. + - [QTBUG-30712][VS] Fixed handling of QMAKE_LIBFLAGS. + - [QTBUG-30373][VS] Using different RESOURCES in different build variants + no longer produces invalid vcxproj files. + - [QTBUG-37520][VS] Made it possible to suppress qmake warnings about + unknown compiler options. CONFIG+=suppress_vcproj_warnings. + - [QTBUG-37363][MSVC2012+] embed_manifest_exe is now properly supported. + - [QTBUG-41504][MSVC2012+] Building DLLs targeting Windows XP is now + supported. As a side effect, Windows CE makespecs must not add /ENTRY: to + QMAKE_LFLAGS_CONSOLE any more. The flag is hard-coded in console.prf now. + - [QTBUG-35318][Xcode] Fixed QMAKE_BUNDLE_DATA's path resolution. + - [QTBUG-39527] Fixed qtCompile() when used with jom -jN. + - QMAKE_EXTRA_COMPILERS' commands and depend_command are no longer mangled. + Use $$shell_path() and $$shell_quote() to prepare the commands correctly. + - Added link-time optimization support for Clang, GCC and ICC. CONFIG+=ltgc. From 19a920c4604b7edfb1632ac30281a1e498a838b0 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 13 Nov 2014 10:32:03 +0100 Subject: [PATCH 282/323] Doc: correct autolink issues corelib/mimetype Task-number: QTBUG-40362 Change-Id: I852151fdbbe0cbc7ba88066984fc7bf83547b215 Reviewed-by: Martin Smith --- src/corelib/mimetypes/qmimedatabase.cpp | 4 ++-- src/corelib/mimetypes/qmimetype.cpp | 4 ++-- src/corelib/tools/qbytearray.cpp | 9 +++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index 9d14e5f90b..c5103ebe59 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -248,7 +248,7 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) \endcode On a typical Unix system, this will be /usr/share/mime/packages/, but it is also possible to extend the list of directories by setting the environment variable - XDG_DATA_DIRS. For instance adding /opt/myapp/share to XDG_DATA_DIRS will result + \c XDG_DATA_DIRS. For instance adding /opt/myapp/share to \c XDG_DATA_DIRS will result in /opt/myapp/share/mime/packages/ being searched for MIME definitions. Here is an example of MIME XML: @@ -575,7 +575,7 @@ QMimeType QMimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, con This can be useful for showing all MIME types to the user, for instance in a MIME type editor. Do not use unless really necessary in other cases - though, prefer using the mimeTypeFor* methods for performance reasons. + though, prefer using the \l {mimeTypeForData()}{mimeTypeForXxx()} methods for performance reasons. */ QList QMimeDatabase::allMimeTypes() const { diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index d1bf27eae0..1ad2a449c1 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -89,8 +89,8 @@ void QMimeTypePrivate::addGlobPattern(const QString &pattern) Determining the MIME type of a file can be useful to make sure your application supports it. It is also useful in file-manager-like applications - or widgets, in order to display an appropriate icon() for the file, or even - the descriptive comment() in detailed views. + or widgets, in order to display an appropriate \l {QMimeType::iconName}{icon} for the file, or even + the descriptive \l {QMimeType::comment()}{comment} in detailed views. To check if a file has the expected MIME type, you should use inherits() rather than a simple string comparison based on the name(). This is because diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index dd235ef7a5..a622221bd3 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -725,7 +725,7 @@ static inline char qToLower(char c) occurrences of a particular value with another, use one of the two-parameter replace() overloads. - QByteArrays can be compared using overloaded operators such as + {QByteArray}s can be compared using overloaded operators such as operator<(), operator<=(), operator==(), operator>=(), and so on. The comparison is based exclusively on the numeric values of the characters and is very fast, but is not what a human would @@ -770,7 +770,7 @@ static inline char qToLower(char c) lastIndexOf(), operator<(), operator<=(), operator>(), operator>=(), toLower() and toUpper(). - This issue does not apply to QStrings since they represent + This issue does not apply to {QString}s since they represent characters using Unicode. \sa QString, QBitArray @@ -3105,6 +3105,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) replaced with a single space. Whitespace means any character for which the standard C++ + \c isspace() function returns \c true in the C locale. This includes the ASCII isspace() function returns \c true in the C locale. This includes the ASCII characters '\\t', '\\n', '\\v', '\\f', '\\r', and ' '. @@ -3143,13 +3144,13 @@ QByteArray QByteArray::simplified() const and the end. Whitespace means any character for which the standard C++ - isspace() function returns \c true in the C locale. This includes the ASCII + \c isspace() function returns \c true in the C locale. This includes the ASCII characters '\\t', '\\n', '\\v', '\\f', '\\r', and ' '. Example: \snippet code/src_corelib_tools_qbytearray.cpp 33 - Unlike simplified(), trimmed() leaves internal whitespace alone. + Unlike simplified(), \l {QByteArray::trimmed()}{trimmed()} leaves internal whitespace alone. \sa simplified() */ From 8ed994f7acd0988a7399e89c2c8f58309754c1c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 3 Sep 2014 16:52:23 +0200 Subject: [PATCH 283/323] iOS: Make sure QStandardPaths::displayName() is defined The file qstandardpaths_ios.mm doesn't have an implementation for this function, only (the wrongly named) qstandardpaths_mac.cpp does. There's no Foundation API to get the directory name, so we fall back to the hard-coded strings like all other platforms. Change-Id: I6dcfeb6a0e5860dd0d4e9a0cd334b2c2181a0004 Reviewed-by: Richard Moe Gustavsen --- src/corelib/io/qstandardpaths.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index 2583e46ad8..c206e432f6 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -526,7 +526,7 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr an empty QString if no relevant location can be found. */ -#if !defined(Q_OS_MAC) && !defined(QT_BOOTSTRAPPED) +#if !defined(Q_OS_OSX) && !defined(QT_BOOTSTRAPPED) QString QStandardPaths::displayName(StandardLocation type) { switch (type) { From 7ca909a11931c63193223474854a98a572c05572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Wed, 17 Sep 2014 12:23:19 +0200 Subject: [PATCH 284/323] Enable tst_qfiledialog2 on OSX Change-Id: I7147d326b0f5bb218f4dbc013ed82efb4c1e1440 Reviewed-by: Marc Mutz Reviewed-by: Paul Olav Tvete --- tests/auto/widgets/dialogs/qfiledialog2/qfiledialog2.pro | 1 - tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/widgets/dialogs/qfiledialog2/qfiledialog2.pro b/tests/auto/widgets/dialogs/qfiledialog2/qfiledialog2.pro index 5239614fc7..fb432a7d21 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/qfiledialog2.pro +++ b/tests/auto/widgets/dialogs/qfiledialog2/qfiledialog2.pro @@ -20,4 +20,3 @@ wince* { DEFINES += SRCDIR=\\\"$$PWD/\\\" } -macx:CONFIG += insignificant_test # QTBUG-39183 diff --git a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp index 2ffb81a751..241e6d0e7e 100644 --- a/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog2/tst_qfiledialog2.cpp @@ -448,6 +448,8 @@ void tst_QFileDialog2::task180459_lastDirectory_data() void tst_QFileDialog2::task180459_lastDirectory() { + if (qApp->platformName().toLower() == QStringLiteral("cocoa")) + QSKIP("Insignificant on OSX"); //QTBUG-39183 //first visit the temp directory and close the dialog QNonNativeFileDialog *dlg = new QNonNativeFileDialog(0, "", tempDir.path()); QFileSystemModel *model = dlg->findChild("qt_filesystem_model"); From 9d8f51861ef53fa8b10e19214b713d55481b8316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Wed, 17 Sep 2014 10:32:56 +0200 Subject: [PATCH 285/323] Enable tst_QGraphicsView on OSX Change-Id: If1cec2ff90ff0a4bdcfdd0e21aa5c2118ce4e862 Reviewed-by: Paul Olav Tvete --- .../widgets/graphicsview/qgraphicsview/qgraphicsview.pro | 1 - .../graphicsview/qgraphicsview/tst_qgraphicsview.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/qgraphicsview.pro b/tests/auto/widgets/graphicsview/qgraphicsview/qgraphicsview.pro index 201085aecd..d1f9bede0b 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/qgraphicsview.pro +++ b/tests/auto/widgets/graphicsview/qgraphicsview/qgraphicsview.pro @@ -9,5 +9,4 @@ SOURCES += tst_qgraphicsview.cpp tst_qgraphicsview_2.cpp HEADERS += tst_qgraphicsview.h DEFINES += QT_NO_CAST_TO_ASCII -mac:CONFIG+=insignificant_test # QTBUG-26580 DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index afd8be71e8..250790d9fa 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -143,6 +143,10 @@ class tst_QGraphicsView : public QObject { Q_OBJECT +public: + tst_QGraphicsView() + : platformName(qApp->platformName().toLower()) + { } private slots: void initTestCase(); void cleanup(); @@ -272,6 +276,7 @@ private: #if defined Q_OS_BLACKBERRY QScopedPointer rootWindow; #endif + QString platformName; }; void tst_QGraphicsView::initTestCase() @@ -2828,6 +2833,8 @@ void tst_QGraphicsView::scrollBarRanges() if (style == QLatin1String("GTK+") && useStyledPanel) QSKIP("GTK + style test skipped, see QTBUG-29002"); + if (useStyledPanel && style == QStringLiteral("Macintosh") && platformName == QStringLiteral("cocoa")) + QSKIP("Insignificant on OSX"); QGraphicsScene scene; QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); @@ -4734,6 +4741,8 @@ public: void tst_QGraphicsView::hoverLeave() { + if (platformName == QStringLiteral("cocoa")) + QSKIP("Insignificant on OSX"); const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry(); QGraphicsScene scene; QGraphicsView view(&scene); From 2ca323ccd4f25f409eff8fc0c9804099b78c2bde Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 11 Nov 2014 13:11:54 +0100 Subject: [PATCH 286/323] Android: Compile for MIPS The qt_memfill32_asm_mips_dsp function is only declared if QT_COMPILER_SUPPORTS_MIPS_DSP is defined, so we can't reference it unless the same macro is defined. Change-Id: Ib959b4b969b699ca78804394206266469b4ebf64 Task-number: QTBUG-36017 Reviewed-by: Paul Olav Tvete Reviewed-by: Thiago Macieira --- src/gui/painting/qdrawhelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index f2d27a0e2a..6482cc50f7 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6829,7 +6829,7 @@ void qInitDrawhelperAsm() qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; #endif -#ifdef Q_PROCESSOR_MIPS_32 +#if defined(Q_PROCESSOR_MIPS_32) && defined(QT_COMPILER_SUPPORTS_MIPS_DSP) qt_memfill32 = qt_memfill32_asm_mips_dsp; #endif // Q_PROCESSOR_MIPS_32 From bec1854cc023fb705319c582a636d5f484adafcc Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 16 Nov 2014 17:36:27 +0100 Subject: [PATCH 287/323] QSortFilterProxyModel: keep the sorting on unrelated changes Whenever the source model of a QSortFilterProxyModel changes, and the changes involve the sorted column, the implementation removes the changed rows from the mapping, sorts them, and inserts them back; in case of identical items, the rows are inserted at the end of the block of equal rows. The problem is that if the change doesn't actually happen on the roles that are used for sorting, then we shuffle the rows, terribly confusing the user. The typical case is a model with identical checkable rows: (un)checking one row will move it at the end. So, instead of trying to be smart with the removal/sort/insert sorted, simply resort everything under the changed parent index. Since the sorting used is stable, this keeps the items in the same positions. Task-number: QTBUG-1548 Change-Id: Id0e61bd49da53b0a3e8aefa6b6893ac41179dc6f Reviewed-by: David Faure --- .../itemmodels/qsortfilterproxymodel.cpp | 6 +- .../tst_qsortfilterproxymodel.cpp | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index a95c7dc8b3..3c383532bb 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -1196,11 +1196,7 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc parents << q->mapFromSource(source_parent); emit q->layoutAboutToBeChanged(parents, QAbstractItemModel::VerticalSortHint); QModelIndexPairList source_indexes = store_persistent_indexes(); - remove_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); - sort_source_rows(source_rows_resort, source_parent); - insert_source_items(m->proxy_rows, m->source_rows, source_rows_resort, - source_parent, Qt::Vertical, false); + sort_source_rows(m->source_rows, source_parent); update_persistent_indexes(source_indexes); emit q->layoutChanged(parents, QAbstractItemModel::VerticalSortHint); // Make sure we also emit dataChanged for the rows diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index ed84c111c6..38a274947f 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -95,6 +95,7 @@ private slots: void changeFilter(); void changeSourceData_data(); void changeSourceData(); + void changeSourceDataKeepsStableSorting_qtbug1548(); void sortFilterRole(); void selectionFilteredOut(); void match_data(); @@ -2009,6 +2010,79 @@ void tst_QSortFilterProxyModel::changeSourceData() } } +// Checks that the model is a table, and that each and every row is like this: +// i-th row: ( rows.at(i), i ) +static void checkSortedTableModel(const QAbstractItemModel *model, const QStringList &rows) +{ + QCOMPARE(model->rowCount(), rows.length()); + QCOMPARE(model->columnCount(), 2); + + for (int row = 0; row < model->rowCount(); ++row) { + const QString column0 = model->index(row, 0).data().toString(); + const int column1 = model->index(row, 1).data().toString().toInt(); + + QCOMPARE(column0, rows.at(row)); + QCOMPARE(column1, row); + } +} + +void tst_QSortFilterProxyModel::changeSourceDataKeepsStableSorting_qtbug1548() +{ + // Check that emitting dataChanged from the source model + // for a change of a role which is not the sorting role + // doesn't alter the sorting. In this case, we sort on the DisplayRole, + // and play with other roles. + + static const QStringList rows + = QStringList() << "a" << "b" << "b" << "b" << "c" << "c" << "x"; + + // Build a table of pairs (string, #row) in each row + QStandardItemModel model(0, 2); + + for (int rowNumber = 0; rowNumber < rows.length(); ++rowNumber) { + QStandardItem *column0 = new QStandardItem(rows.at(rowNumber)); + column0->setCheckable(true); + column0->setCheckState(Qt::Unchecked); + + QStandardItem *column1 = new QStandardItem(QString::number(rowNumber)); + + const QList row + = QList() << column0 << column1; + + model.appendRow(row); + } + + checkSortedTableModel(&model, rows); + + // Build the proxy model + QSortFilterProxyModel proxy; + proxy.setSourceModel(&model); + proxy.setDynamicSortFilter(true); + proxy.sort(0); + + // The proxy is now sorted by the first column, check that the sorting + // * is correct (the input is already sorted, so it must not have changed) + // * was stable (by looking at the second column) + checkSortedTableModel(&model, rows); + + // Change the check status of an item. That must not break the stable sorting + // changes the middle "b" + model.item(2)->setCheckState(Qt::Checked); + checkSortedTableModel(&model, rows); + + // changes the starting "a" + model.item(0)->setCheckState(Qt::Checked); + checkSortedTableModel(&model, rows); + + // change the background color of the first "c" + model.item(4)->setBackground(Qt::red); + checkSortedTableModel(&model, rows); + + // change the background color of the second "c" + model.item(5)->setBackground(Qt::red); + checkSortedTableModel(&model, rows); +} + void tst_QSortFilterProxyModel::sortFilterRole() { QStandardItemModel model; From 41db4b8cdc231eaeef9d1bb144f134901c45a2ef Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 19 Nov 2014 14:01:47 +0100 Subject: [PATCH 288/323] Enable transformations for Qt Quick in FT engine In Qt Quick (or in Qt Widgets when setting QT_NO_FT_CACHE to 1 or when using OpenGL engine), the alphaRGBMapForGlyph() will be used to get glyphs, because we need to keep our own cache. Transforms was not supported in this code path, instead it was turned off in supportsTransformations(). This patch enables transformations in the alphaRGBMapForGlyph() and alphaMapForGlyph() code paths as well, since this is needed for proper rendering with QT_DEVICE_PIXEL_RATIO. Change-Id: I7d6b79918f7c0bcc051a8343b16b315bfbba59cf Reviewed-by: Konstantin Ritt Reviewed-by: Lars Knoll --- src/gui/text/qfontengine_ft.cpp | 75 ++++++++++++++++++++++++++++----- src/gui/text/qfontengine_ft_p.h | 3 +- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index b0cfa49b36..83d9edab94 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1459,10 +1459,7 @@ void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_me bool QFontEngineFT::supportsTransformation(const QTransform &transform) const { - // The freetype engine falls back to QFontEngine for tranformed glyphs, - // which uses fast-tranform and produces very ugly results, so we claim - // to support just translations. - return transform.type() <= QTransform::TxTranslate; + return transform.type() <= QTransform::TxRotate; } void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) @@ -1943,17 +1940,75 @@ void QFontEngineFT::unlockAlphaMapForGlyph() currentlyLockedAlphaMap = QImage(); } -QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format) +QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, + QFixed subPixelPosition, + GlyphFormat format, + const QTransform &t) { - return defaultGlyphSet.outline_drawing ? 0 : - loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format); + FT_Face face = 0; + QGlyphSet *glyphSet = 0; + FT_Matrix ftMatrix = QTransformToFTMatrix(t); + if (cacheEnabled) { + if (t.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) { + for (int i = 0; i < transformedGlyphSets.count(); ++i) { + const QGlyphSet &g = transformedGlyphSets.at(i); + if (g.transformationMatrix.xx == ftMatrix.xx + && g.transformationMatrix.xy == ftMatrix.xy + && g.transformationMatrix.yx == ftMatrix.yx + && g.transformationMatrix.yy == ftMatrix.yy) { + + // found a match, move it to the front + transformedGlyphSets.move(i, 0); + glyphSet = &transformedGlyphSets[0]; + break; + } + } + + if (!glyphSet) { + // don't cache more than 10 transformations + if (transformedGlyphSets.count() >= 10) { + transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0); + } else { + transformedGlyphSets.prepend(QGlyphSet()); + } + glyphSet = &transformedGlyphSets[0]; + glyphSet->clear(); + glyphSet->transformationMatrix = ftMatrix; + } + } else { + glyphSet = &defaultGlyphSet; + } + Q_ASSERT(glyphSet != 0); + } + + if (glyphSet != 0 && glyphSet->outline_drawing) + return 0; + + Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0; + if (!glyph || glyph->format != format) { + face = lockFace(); + FT_Matrix m = this->matrix; + FT_Matrix_Multiply(&ftMatrix, &m); + freetype->matrix = m; + glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false); + } + + if (face) + unlockFace(); + + return glyph; } QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) +{ + return alphaMapForGlyph(g, subPixelPosition, QTransform()); +} + +QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) { lockFace(); - QScopedPointer glyph(loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono)); + QScopedPointer glyph(loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono, t)); if (!glyph || !glyph->data) { unlockFace(); return QFontEngine::alphaMapForGlyph(g); @@ -1987,12 +2042,12 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition) QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t) { - if (t.type() > QTransform::TxTranslate) + if (t.type() > QTransform::TxRotate) return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); lockFace(); - QScopedPointer glyph(loadGlyphFor(g, subPixelPosition, Format_A32)); + QScopedPointer glyph(loadGlyphFor(g, subPixelPosition, Format_A32, t)); if (!glyph || !glyph->data) { unlockFace(); return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t); diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index a73c281f1d..1894d25d70 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -233,6 +233,7 @@ private: virtual void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const; virtual QImage alphaMapForGlyph(glyph_t g) { return alphaMapForGlyph(g, 0); } virtual QImage alphaMapForGlyph(glyph_t, QFixed); + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t); virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t); virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, @@ -265,7 +266,7 @@ private: inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false) const { return loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, subPixelPosition, format, fetchMetricsOnly); } Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false) const; - Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format); + Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t); QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); bool loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs, From 71ed74e72e4d3c643381fa1b4a276c0609393df2 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Mon, 10 Nov 2014 12:53:31 +0100 Subject: [PATCH 289/323] Allow empty string as intermediate match QRegularExpressionValidator and QRegularExpression disagree on what a partial match means. [ChangeLog][QtGui][QRegularExpressionValidator] Allow empty string as intermediate match Change-Id: Ia6c55beb54870b1be5c88b6ef3eceebc8ca3f86b Reviewed-by: Giuseppe D'Angelo --- src/gui/util/qvalidator.cpp | 2 +- .../tst_qregularexpressionvalidator.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index 93990a8748..aac9282710 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -1013,7 +1013,7 @@ QValidator::State QRegularExpressionValidator::validate(QString &input, int &pos const QRegularExpressionMatch m = d->usedRe.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); if (m.hasMatch()) { return Acceptable; - } else if (m.hasPartialMatch()) { + } else if (input.isEmpty() || m.hasPartialMatch()) { return Intermediate; } else { pos = input.size(); diff --git a/tests/auto/gui/util/qregularexpressionvalidator/tst_qregularexpressionvalidator.cpp b/tests/auto/gui/util/qregularexpressionvalidator/tst_qregularexpressionvalidator.cpp index 31853f7015..eff07ad07f 100644 --- a/tests/auto/gui/util/qregularexpressionvalidator/tst_qregularexpressionvalidator.cpp +++ b/tests/auto/gui/util/qregularexpressionvalidator/tst_qregularexpressionvalidator.cpp @@ -74,6 +74,9 @@ void tst_QRegularExpressionValidator::validate_data() QTest::newRow("data14") << QRegularExpression("\\w\\d\\d") << QString("E5") << QValidator::Intermediate; QTest::newRow("data15") << QRegularExpression("\\w\\d\\d") << QString("+9") << QValidator::Invalid; + QTest::newRow("emptystr1") << QRegularExpression("[T][e][s][t]") << QString("") << QValidator::Intermediate; + QTest::newRow("emptystr2") << QRegularExpression("[T][e][s][t]") << QString() << QValidator::Intermediate; + QTest::newRow("empty01") << QRegularExpression() << QString() << QValidator::Acceptable; QTest::newRow("empty02") << QRegularExpression() << QString("test") << QValidator::Acceptable; } From d29d727d720fa4ac7ba046b6bfb96707586de7d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Thu, 20 Nov 2014 14:56:22 +0200 Subject: [PATCH 290/323] fix how qnetworkreply autotests are blacklisted Change-Id: Id5b0ec07504020f246e57d3ad57ffd5ce0be61ab Reviewed-by: Simon Hausmann --- tests/auto/network/access/qnetworkreply/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index 504396bdd1..7792e05e0f 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -7,4 +7,6 @@ osx [SslHandshakeFailedError] osx [httpAbort] +* [backgroundRequestInterruption:ftp, bg, nobg] +* From 07f234d2a8283081aabdd1465f09b04a26bec1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tony=20Saraj=C3=A4rvi?= Date: Thu, 20 Nov 2014 14:54:25 +0200 Subject: [PATCH 291/323] Fix how qsocks5socketengine autotests are blacklisted Change-Id: I6436491267b737fc00c33af7bd9491510c21b7c5 Reviewed-by: Simon Hausmann --- tests/auto/network/socket/qsocks5socketengine/BLACKLIST | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST index 1bc24299e8..bf4afa8c45 100644 --- a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -1,2 +1,4 @@ [udpTest] +* [passwordAuth] +* From 1d9d8123de4e40abe2ceb2e99c82634d0a2ecc65 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 19 Nov 2014 09:40:43 +0100 Subject: [PATCH 292/323] Text editors: Prevent autoscroll timer triggering from synth mouse events The autoscrolling interferes with scrolling pan gestures and causes the scroll direction to be reversed when moving outside the window. Task-number: QTBUG-40461 Change-Id: I30ef848a346418929540c23730ab92f44e4565e2 Reviewed-by: Shawn Rutledge --- src/widgets/widgets/qplaintextedit.cpp | 14 ++++++++------ src/widgets/widgets/qtextedit.cpp | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index b6a21f183a..72a556db7c 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -2042,11 +2042,13 @@ void QPlainTextEdit::mouseMoveEvent(QMouseEvent *e) d->sendControlEvent(e); if (!(e->buttons() & Qt::LeftButton)) return; - QRect visible = d->viewport->rect(); - if (visible.contains(pos)) - d->autoScrollTimer.stop(); - else if (!d->autoScrollTimer.isActive()) - d->autoScrollTimer.start(100, this); + if (e->source() == Qt::MouseEventNotSynthesized) { + const QRect visible = d->viewport->rect(); + if (visible.contains(pos)) + d->autoScrollTimer.stop(); + else if (!d->autoScrollTimer.isActive()) + d->autoScrollTimer.start(100, this); + } } /*! \reimp @@ -2055,7 +2057,7 @@ void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e) { Q_D(QPlainTextEdit); d->sendControlEvent(e); - if (d->autoScrollTimer.isActive()) { + if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) { d->autoScrollTimer.stop(); d->ensureCursorVisible(); } diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 2d95009eb3..7ef864139f 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -1574,11 +1574,13 @@ void QTextEdit::mouseMoveEvent(QMouseEvent *e) d->sendControlEvent(e); if (!(e->buttons() & Qt::LeftButton)) return; - QRect visible = d->viewport->rect(); - if (visible.contains(pos)) - d->autoScrollTimer.stop(); - else if (!d->autoScrollTimer.isActive()) - d->autoScrollTimer.start(100, this); + if (e->source() == Qt::MouseEventNotSynthesized) { + const QRect visible = d->viewport->rect(); + if (visible.contains(pos)) + d->autoScrollTimer.stop(); + else if (!d->autoScrollTimer.isActive()) + d->autoScrollTimer.start(100, this); + } } /*! \reimp @@ -1587,7 +1589,7 @@ void QTextEdit::mouseReleaseEvent(QMouseEvent *e) { Q_D(QTextEdit); d->sendControlEvent(e); - if (d->autoScrollTimer.isActive()) { + if (e->source() == Qt::MouseEventNotSynthesized && d->autoScrollTimer.isActive()) { d->autoScrollTimer.stop(); ensureCursorVisible(); } From 6bded1695b0b1b562a0dbf8d50f469a1c6326ebc Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Sat, 8 Nov 2014 12:28:16 +0200 Subject: [PATCH 293/323] Fix QString::section() behavior on negative and out-of-range indexes Change-Id: I3bff6ba73b15ee810bb11b2902d11244c3205b2a Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 57 +++++++++++++------ .../corelib/tools/qstring/tst_qstring.cpp | 22 +++++++ 2 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 543c75668f..ed581e43e9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3863,28 +3863,31 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl { QStringList sections = split(sep, KeepEmptyParts, (flags & SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive : Qt::CaseSensitive); - if (sections.isEmpty()) - return QString(); + const int sectionsSize = sections.size(); + if (!(flags & SectionSkipEmpty)) { if (start < 0) - start += sections.count(); + start += sectionsSize; if (end < 0) - end += sections.count(); + end += sectionsSize; } else { int skip = 0; - for (int k=0; k= sectionsSize || end < 0 || start > end) + return QString(); + int x = 0; QString ret; int first_i = start, last_i = end; - for (int i = 0; x <= end && i < sections.size(); ++i) { + for (int i = 0; x <= end && i < sectionsSize; ++i) { QString section = sections.at(i); const bool empty = section.isEmpty(); if (x >= start) { @@ -3892,16 +3895,16 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl first_i = i; if(x == end) last_i = i; - if(x > start) + if (x > start && i > 0) ret += sep; ret += section; } if (!empty || !(flags & SectionSkipEmpty)) x++; } - if((flags & SectionIncludeLeadingSep) && first_i) + if ((flags & SectionIncludeLeadingSep) && first_i > 0) ret.prepend(sep); - if((flags & SectionIncludeTrailingSep) && last_i < sections.size()-1) + if ((flags & SectionIncludeTrailingSep) && last_i < sectionsSize - 1) ret += sep; return ret; } @@ -3919,15 +3922,32 @@ static QString extractSections(const QList §ions, int end, QString::SectionFlags flags) { - if (start < 0) - start += sections.count(); - if (end < 0) - end += sections.count(); + const int sectionsSize = sections.size(); + + if (!(flags & QString::SectionSkipEmpty)) { + if (start < 0) + start += sectionsSize; + if (end < 0) + end += sectionsSize; + } else { + int skip = 0; + for (int k = 0; k < sectionsSize; ++k) { + const qt_section_chunk §ion = sections.at(k); + if (section.length == section.string.length()) + skip++; + } + if (start < 0) + start += sectionsSize - skip; + if (end < 0) + end += sectionsSize - skip; + } + if (start >= sectionsSize || end < 0 || start > end) + return QString(); QString ret; int x = 0; int first_i = start, last_i = end; - for (int i = 0; x <= end && i < sections.size(); ++i) { + for (int i = 0; x <= end && i < sectionsSize; ++i) { const qt_section_chunk §ion = sections.at(i); const bool empty = (section.length == section.string.length()); if (x >= start) { @@ -3944,12 +3964,13 @@ static QString extractSections(const QList §ions, x++; } - if ((flags & QString::SectionIncludeLeadingSep) && first_i < sections.size()) { + if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) { const qt_section_chunk §ion = sections.at(first_i); ret.prepend(section.string.left(section.length)); } - if ((flags & QString::SectionIncludeTrailingSep) && last_i+1 <= sections.size()-1) { + if ((flags & QString::SectionIncludeTrailingSep) + && last_i < sectionsSize - 1) { const qt_section_chunk §ion = sections.at(last_i+1); ret += section.string.left(section.length); } diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 3edc9cc965..ea40c64c89 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -4389,6 +4389,28 @@ void tst_QString::section_data() << QString("o") << 1 << 2 << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep) << QString("o1o2o") << false; + QTest::newRow( "range1" ) << QString("o1o2o") + << QString("o") << -5 << -5 + << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep) + << QString() << false; + QTest::newRow( "range2" ) << QString("oo1o2o") + << QString("o") << -5 << 1 + << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep + |QString::SectionSkipEmpty) + << QString("oo1o2o") << false; + QTest::newRow( "range3" ) << QString("o1o2o") + << QString("o") << 2 << 1 + << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep) + << QString() << false; + QTest::newRow( "range4" ) << QString("o1o2o") + << QString("o") << 4 << 4 + << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep) + << QString() << false; + QTest::newRow( "range5" ) << QString("o1oo2o") + << QString("o") << -2 << -1 + << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep + |QString::SectionSkipEmpty) + << QString("o1oo2o") << false; QTest::newRow( "rx1" ) << QString("o1o2o") << QString("[a-z]") << 0 << 0 << int(QString::SectionIncludeLeadingSep|QString::SectionIncludeTrailingSep) From cf0d96f4c8584a7eb9eeca304932f6ea88894b27 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 18 Nov 2014 12:19:22 +0100 Subject: [PATCH 294/323] QWidgetTextControl: Suppress drag selection for OS-synthesized mouse events. Add a convenience function to QApplicationPrivate returning the source of mouse events to be able to detect synthesized mouse events. Change-Id: I09f82ed917586cd3de8b4146fc6638d19d428163 Task-number: QTBUG-40461 Reviewed-by: Shawn Rutledge --- src/widgets/kernel/qapplication.cpp | 26 ++++++++++++++++++++++ src/widgets/kernel/qapplication_p.h | 1 + src/widgets/widgets/qwidgettextcontrol.cpp | 9 +++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 269fe452c1..82b9fec37f 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -53,6 +53,7 @@ #include "qtranslator.h" #include "qvariant.h" #include "qwidget.h" +#include "qgraphicssceneevent.h" #include "private/qdnd_p.h" #include "private/qguiapplication_p.h" #include "qcolormap.h" @@ -2286,6 +2287,31 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool return w; } +Qt::MouseEventSource QApplicationPrivate::mouseEventSource(const QEvent *e) +{ + switch (e->type()) { + case QEvent::NonClientAreaMouseButtonDblClick: + case QEvent::NonClientAreaMouseButtonPress: + case QEvent::NonClientAreaMouseButtonRelease: + case QEvent::NonClientAreaMouseMove: + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + return static_cast(e)->source(); +#ifndef QT_NO_GRAPHICSVIEW + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMousePress: + case QEvent::GraphicsSceneMouseRelease: + case QEvent::GraphicsSceneMouseMove: + return static_cast(e)->source(); +#endif // !QT_NO_GRAPHICSVIEW + default: + break; + } + return Qt::MouseEventNotSynthesized; +} + /*! \fn void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF) \internal diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 7d97235c66..b24b592fbe 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -168,6 +168,7 @@ public: static void setFocusWidget(QWidget *focus, Qt::FocusReason reason); static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next, bool *wrappingOccurred = 0); + static Qt::MouseEventSource mouseEventSource(const QEvent *e); #ifndef QT_NO_GRAPHICSVIEW // Maintain a list of all scenes to ensure font and palette propagation to diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index dfec6a14d4..8f017b7b87 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1580,8 +1580,10 @@ void QWidgetTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton butto cursor.clearSelection(); } } + // Do not start selection on a mouse event synthesized from a touch event. if (!(button & Qt::LeftButton) || - !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) { + !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable)) + || QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) { e->ignore(); return; } @@ -1752,6 +1754,11 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but { Q_Q(QWidgetTextControl); + if (QApplicationPrivate::mouseEventSource(e) != Qt::MouseEventNotSynthesized) { + setCursorPosition(pos); // Emulate Tap to set cursor for events synthesized from touch. + return; + } + const QTextCursor oldSelection = cursor; if (sendMouseEventToInputContext( e, QEvent::MouseButtonRelease, button, pos, modifiers, buttons, globalPos)) { From 2ffa46054d13c639cf9f7846a74ad3ebd07b9f5c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 10 Nov 2014 10:52:22 +0100 Subject: [PATCH 295/323] Use single finger pan to scroll text edits on touch screens. Change the number of pan points to 1 for these classes as a workaround until pan/tap gestures are fully fixed. Task-number: QTBUG-40461 Change-Id: I0d68726a545ee6148f3ab88f2ab7308b10464ecd Reviewed-by: Shawn Rutledge --- src/widgets/kernel/qstandardgestures.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/widgets/kernel/qstandardgestures.cpp b/src/widgets/kernel/qstandardgestures.cpp index 6656903e70..53e5d091fa 100644 --- a/src/widgets/kernel/qstandardgestures.cpp +++ b/src/widgets/kernel/qstandardgestures.cpp @@ -38,6 +38,7 @@ #include "qwidget.h" #include "qabstractscrollarea.h" #include +#include #include "qdebug.h" #ifndef QT_NO_GESTURES @@ -67,8 +68,26 @@ static QPointF panOffset(const QList &touchPoints, int return result / qreal(count); } +// ### fixme: Remove this +// Use single finger pan to scroll QPlainTextEdit/QTextEdit +// by changing the number of pan points to 1 for these classes. +// This used to be Qt 4's behavior on Windows which was achieved using native +// Windows gesture recognizers for these classes. +// The other classes inheriting QScrollArea still use standard 2 finger pan. +// In the long run, they should also use single finger pan to +// scroll on touch screens, however, this requires a distinct Tap&Hold-followed-by-pan +// type gesture to avoid clashes with item view selection and DnD. + +static inline int panTouchPoints(const QTouchEvent *event, const QObject *object, + int defaultTouchPoints) +{ + return event->device()->type() == QTouchDevice::TouchScreen && object && object->parent() + && (object->parent()->inherits("QPlainTextEdit") || object->parent()->inherits("QTextEdit")) + ? 1 : defaultTouchPoints; +} + QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, - QObject *, + QObject *object, QEvent *event) { QPanGesture *q = static_cast(state); @@ -81,7 +100,7 @@ QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, result = QGestureRecognizer::MayBeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastOffset = d->offset = QPointF(); - d->pointCount = m_pointCount; + d->pointCount = panTouchPoints(ev, object, m_pointCount); break; } case QEvent::TouchEnd: { From fbfc2b8e0b0edf9baa69193a96a57a6a6aa6cfaf Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Tue, 11 Nov 2014 13:23:55 +0100 Subject: [PATCH 296/323] Doc: corrected autolink issues itemmodels Task-number: QTBUG-40362 Change-Id: I8423643e47d27358dbbce58009cc9039aecb74cf Reviewed-by: Martin Smith --- src/corelib/itemmodels/qabstractitemmodel.cpp | 8 ++++---- src/corelib/itemmodels/qitemselectionmodel.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 6b89c8377a..b15d255e66 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -2711,7 +2711,7 @@ bool QAbstractItemModelPrivate::allowMove(const QModelIndex &srcParent, int star persistent indexes in the model, which you would otherwise be required to do yourself. Using beginMoveRows and endMoveRows is an alternative to emitting layoutAboutToBeChanged and - layoutChanged directly along with changePersistentIndexes. + layoutChanged directly along with changePersistentIndex. The \a sourceParent index corresponds to the parent from which the rows are moved; \a sourceFirst and \a sourceLast are the first and last @@ -2978,7 +2978,7 @@ void QAbstractItemModel::endRemoveColumns() persistent indexes in the model, which you would otherwise be required to do yourself. Using beginMoveRows and endMoveRows is an alternative to emitting layoutAboutToBeChanged and - layoutChanged directly along with changePersistentIndexes. + layoutChanged directly along with changePersistentIndex. The \a sourceParent index corresponds to the parent from which the columns are moved; \a sourceFirst and \a sourceLast are the first and last @@ -3165,11 +3165,11 @@ void QAbstractItemModel::changePersistentIndex(const QModelIndex &from, const QM /*! \since 4.1 - Changes the QPersistentModelIndexes that is equal to the indexes in the + Changes the {QPersistentModelIndex}es that are equal to the indexes in the given \a from model index list to the given \a to model index list. If no persistent model indexes equal to the indexes in the given \a from - model index list was found, nothing is changed. + model index list are found, nothing is changed. \sa persistentIndexList(), changePersistentIndex() */ diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp index db78af8cf8..5395fd5d09 100644 --- a/src/corelib/itemmodels/qitemselectionmodel.cpp +++ b/src/corelib/itemmodels/qitemselectionmodel.cpp @@ -1076,7 +1076,7 @@ void QItemSelectionModelPrivate::_q_layoutChanged(const QList Date: Wed, 19 Nov 2014 15:25:27 +0100 Subject: [PATCH 297/323] Doc: Corrected autolink errors corelib Task-number: QTBUG-40362 Change-Id: I551c2af94bb61fcc2494792761dab92d537e5068 Reviewed-by: Martin Smith --- src/corelib/doc/src/animation.qdoc | 6 ++--- src/corelib/doc/src/containers.qdoc | 22 +++++++++---------- src/corelib/doc/src/datastreamformat.qdoc | 2 +- src/corelib/doc/src/filestorage.qdoc | 4 ++-- .../doc/src/objectmodel/signalsandslots.qdoc | 10 ++++----- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc index 5839d42a39..9385c08995 100644 --- a/src/corelib/doc/src/animation.qdoc +++ b/src/corelib/doc/src/animation.qdoc @@ -48,7 +48,7 @@ The animation framework aims to provide an easy way for creating animated and smooth GUIs. By animating Qt properties, the framework provides great - freedom for animating widgets and other \l{QObject}s. The framework can + freedom for animating widgets and other {QObject}s. The framework can also be used with the Graphics View framework. Many of the concepts available in the animation framework are also available in \l{Qt Quick}, where it offers a declarative way of defining animations. Much of the @@ -57,7 +57,7 @@ In this overview, we explain the basics of its architecture. We also show examples of the most common techniques that the - framework allows for animating QObjects and graphics items. + framework allows for animating {QObject}s and graphics items. \tableofcontents @@ -85,7 +85,7 @@ over the property using an easing curve. So when you want to animate a value, you can declare it as a property and make your class a QObject. Note that this gives us great freedom in - animating already existing widgets and other \l{QObject}s. + animating already existing widgets and other {QObject}s. Complex animations can be constructed by building a tree structure of \l{QAbstractAnimation}s. The tree is built by using diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc index 6017269272..a517ca32d3 100644 --- a/src/corelib/doc/src/containers.qdoc +++ b/src/corelib/doc/src/containers.qdoc @@ -386,7 +386,7 @@ \l{QMapIterator::hasPrevious()}{hasPrevious()}, \l{QMapIterator::previous()}{previous()}, and \l{QMapIterator::peekPrevious()}{peekPrevious()}. The key and - value components are extracted by calling key() and value() on + value components are extracted by calling \l{QMapIterator::key()}{key()} and \l{QMapIterator::value()}{value()} on the object returned by next(), peekNext(), previous(), or peekPrevious(). @@ -395,7 +395,7 @@ \snippet code/doc_src_containers.cpp 7 - QMapIterator also provides a key() and a value() function that + QMapIterator also provides a \l{QMapIterator::key()}{key()} and a \l{QMapIterator::value()}{value()} function that operate directly on the iterator and that return the key and value of the last item that the iterator jumped above. For example, the following code copies the contents of a QMap into a @@ -459,13 +459,13 @@ \snippet code/doc_src_containers.cpp 10 Unlike \l{Java-style iterators}, STL-style iterators point - directly at items. The begin() function of a container returns an + directly at items. The \l{QList::begin()}{begin()} function of a container returns an iterator that points to the first item in the container. The - end() function of a container returns an iterator to the + \l{QList::end()}{end()} function of a container returns an iterator to the imaginary item one position past the last item in the container. - end() marks an invalid position; it must never be dereferenced. + \l {QList::end()}{end()} marks an invalid position; it must never be dereferenced. It is typically used in a loop's break condition. If the list is - empty, begin() equals end(), so we never execute the loop. + empty, \l{QList::begin}{begin()} equals \l{QList:end()}{end()}, so we never execute the loop. The diagram below shows the valid iterator positions as red arrows for a vector containing four items: @@ -484,8 +484,8 @@ compilers also allow us to write \c{i->toLower()}, but some don't. - For read-only access, you can use const_iterator, constBegin(), - and constEnd(). For example: + For read-only access, you can use const_iterator, \l{QList::constBegin}{constBegin()}, + and \l{QList::constEnd()}{constEnd()}. For example: \snippet code/doc_src_containers.cpp 12 @@ -759,7 +759,7 @@ QString. QVector also uses that algorithm for data types that can be - moved around in memory using memcpy() (including the basic C++ + moved around in memory using \c memcpy() (including the basic C++ types, the pointer types, and Qt's \l{shared classes}) but uses a different algorithm for data types that can only be moved by calling the copy constructor and a destructor. Since the cost of @@ -790,7 +790,7 @@ \endlist If you know approximately how many items you will store in a - container, you can start by calling reserve(), and when you are - done populating the container, you can call squeeze() to release + container, you can start by calling \l{QString::reserve()}{reserve()}, and when you are + done populating the container, you can call \l{QString::squeeze()}{squeeze()} to release the extra preallocated memory. */ diff --git a/src/corelib/doc/src/datastreamformat.qdoc b/src/corelib/doc/src/datastreamformat.qdoc index b6efe6aa33..56a6d0aafa 100644 --- a/src/corelib/doc/src/datastreamformat.qdoc +++ b/src/corelib/doc/src/datastreamformat.qdoc @@ -173,7 +173,7 @@ \li If the image is null a "null image" marker is saved; otherwise the image is saved in PNG or BMP format (depending on the stream version). If you want control of the format, - stream the image into a QBuffer (using QImageIO) and stream + stream the image into a QBuffer (using QImageIOHandler/QImageIOPlugin) and stream that. \endlist \row \li QKeySequence diff --git a/src/corelib/doc/src/filestorage.qdoc b/src/corelib/doc/src/filestorage.qdoc index 394d920923..a60c5846ff 100644 --- a/src/corelib/doc/src/filestorage.qdoc +++ b/src/corelib/doc/src/filestorage.qdoc @@ -86,8 +86,8 @@ read console input and write console output. There are three general ways to use QTextStream when reading text files: \list - \li Chunk by chunk, by calling readLine() or readAll(). - \li Word by word. QTextStream supports streaming into QStrings, QByteArrays + \li Chunk by chunk, by calling \l{QBuffer::readLine()}{readLine()} or \l{QBuffer::readAll()}{readAll()}. + \li Word by word. QTextStream supports streaming into {QString}s, {QByteArray}s and char* buffers. Words are delimited by space, and leading white space is automatically skipped. \li Character by character, by streaming into QChar or char types. This diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc index f79e8a7dca..b9b1874d0f 100644 --- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc +++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc @@ -242,7 +242,7 @@ By default, for every connection you make, a signal is emitted; two signals are emitted for duplicate connections. You can break - all of these connections with a single disconnect() call. + all of these connections with a single \l{QObject::disconnect()}{disconnect()} call. If you pass the Qt::UniqueConnection \a type, the connection will only be made if it is not a duplicate. If there is already a duplicate (exact same signal to the exact same slot on the same objects), @@ -251,9 +251,7 @@ This example illustrates that objects can work together without needing to know any information about each other. To enable this, the objects only need to be connected together, and this can be achieved with some simple - QObject::connect() function calls, or with \c{uic}'s - \l{Using a Designer UI File in Your Application#Automatic Connections} - {automatic connections} feature. + QObject::connect() function calls, or with \c{uic}'s {automatic connections} feature. \section1 A Real Example @@ -354,7 +352,7 @@ connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed); \endcode - There are several advantages to using connect() with function pointers. + There are several advantages to using QObject::connect() with function pointers. First, it allows the compiler to check that the signal's arguments are compatible with the slot's arguments. Arguments can also be implicitly converted by the compiler, if needed. @@ -407,7 +405,7 @@ will open: "Tax File", "Accounts File", or "Report File". In order to open the correct file, you use QSignalMapper::setMapping() to - map all the clicked() signals to a QSignalMapper object. Then you connect + map all the QPushButton::clicked() signals to a QSignalMapper object. Then you connect the file's QPushButton::clicked() signal to the QSignalMapper::map() slot. \snippet signalmapper/filereader.cpp 0 From 52f5bf9cd5dd5586dc18b2d7efd833232c2f508a Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 19 Nov 2014 18:43:18 +0200 Subject: [PATCH 298/323] Android: Use LocalServerSocket instead of ServerSocket Using LocalServerSocket is way much safer than ServerSocket because is not using ports which might be in use by other applications. Change-Id: I0e2be0b4561362939950861024f1f95ab819f2c2 Reviewed-by: BogDan Vatra Reviewed-by: Alex Blasche Reviewed-by: hjk Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../qt5/android/QtActivityDelegate.java | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 12b606b89f..f44465b4c5 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -50,6 +50,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.graphics.drawable.ColorDrawable; +import android.net.LocalServerSocket; +import android.net.LocalSocket; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -79,9 +81,6 @@ import java.io.FileWriter; import java.io.InputStreamReader; import java.io.IOException; import java.lang.reflect.Method; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -496,12 +495,12 @@ public class QtActivityDelegate private class DebugWaitRunnable implements Runnable { - public DebugWaitRunnable(int socketPort) throws IOException { - socket = new ServerSocket(socketPort); + public DebugWaitRunnable(String pingPongSocket) throws IOException { + socket = new LocalServerSocket(pingPongSocket); } public boolean wasFailure; - private ServerSocket socket; + private LocalServerSocket socket; public void run() { final int napTime = 200; // milliseconds between file accesses @@ -509,9 +508,7 @@ public class QtActivityDelegate final int maxAttempts = timeOut / napTime; try { - socket.setSoTimeout(timeOut); - debugLog("Waiting for debug socket on port: " + socket.getLocalPort()); - Socket connectionFromClient = socket.accept(); + LocalSocket connectionFromClient = socket.accept(); debugLog("Debug socket accepted"); BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionFromClient.getInputStream())); @@ -524,7 +521,7 @@ public class QtActivityDelegate if (!clientData.isEmpty()) break; - if (socket.isClosed()) { + if (connectionFromClient.isClosed()) { wasFailure = true; break; } @@ -539,6 +536,14 @@ public class QtActivityDelegate Log.e(QtNative.QtTAG,"Can't start debugger" + interruptEx.getMessage()); } } + + public void shutdown() throws IOException + { + wasFailure = true; + try { + socket.close(); + } catch (IOException ignored) { } + } }; public boolean startApplication() @@ -597,17 +602,11 @@ public class QtActivityDelegate String pongFile = extras.getString("pong_file"); String gdbserverSocket = extras.getString("gdbserver_socket"); String gdbserverCommand = extras.getString("gdbserver_command"); - String pingViaSocket = extras.getString("ping_socketport"); + String pingSocket = extras.getString("ping_socket"); boolean usePing = pingFile != null; boolean usePong = pongFile != null; boolean useSocket = gdbserverSocket != null; - int pingSocket = 0; - if (pingViaSocket != null) { - try { - pingSocket = Integer.parseInt(pingViaSocket); - } catch (NumberFormatException ignored) { } - } - boolean usePingViaSocket = (pingViaSocket != null && pingSocket > 0); + boolean usePingSocket = pingSocket != null; int napTime = 200; // milliseconds between file accesses int timeOut = 30000; // ms until we give up on ping and pong int maxAttempts = timeOut / napTime; @@ -654,7 +653,7 @@ public class QtActivityDelegate } if (i == maxAttempts) { - debugLog("time out when waiting for socket"); + debugLog("time out when waiting for debug socket"); return false; } @@ -663,11 +662,23 @@ public class QtActivityDelegate debugLog("socket not used"); } - if (usePingViaSocket) { + if (usePingSocket) { DebugWaitRunnable runnable = new DebugWaitRunnable(pingSocket); Thread waitThread = new Thread(runnable); waitThread.start(); - waitThread.join(); + + int i; + for (i = 0; i < maxAttempts && waitThread.isAlive(); ++i) { + debugLog("Waiting for debug socket connect"); + debugLog("go to sleep"); + Thread.sleep(napTime); + } + + if (i == maxAttempts) { + debugLog("time out when waiting for ping socket"); + runnable.shutdown(); + return false; + } if (runnable.wasFailure) { debugLog("Could not connect to debug client"); From 087aa1f3cb5975ef55e42db54487f737c93a4f0f Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 20 Nov 2014 11:08:13 +0100 Subject: [PATCH 299/323] Windows: Prevent registration of timers in shutdown phase Do not register new timers after closingDown() has been called. They might call back into QEventDispatcherWin32 after the object has been destructed, leading to crashes on exit. registerSocketNotifier has a similar protection using QCoreApplication::closingDown(). This however does not work in all cases, because QEventDispatcher::closingDown() is called in ~QGuiApplication(), while QCoreApplication::is_app_closing is set in ~QCoreApplication(). In between qt_call_post_routines() is called, which might trigger new timers to be registered. Task-number: QTBUG-42772 Change-Id: I91325fb10e38c117c1cbedfee272d0ab6a5ca8fa Reviewed-by: Friedemann Kleint --- src/corelib/kernel/qeventdispatcher_win.cpp | 12 ++++++++++-- src/corelib/kernel/qeventdispatcher_win_p.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 62e6e9f051..1a8bb381aa 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -307,8 +307,9 @@ static void resolveTimerAPI() } QEventDispatcherWin32Private::QEventDispatcherWin32Private() - : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0), getMessageHook(0), - serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), wakeUps(0) + : threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0), + getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), + wakeUps(0) { resolveTimerAPI(); } @@ -931,6 +932,11 @@ void QEventDispatcherWin32::registerTimer(int timerId, int interval, Qt::TimerTy Q_D(QEventDispatcherWin32); + // exiting ... do not register new timers + // (QCoreApplication::closingDown() is set too late to be used here) + if (d->closingDown) + return; + WinTimerInfo *t = new WinTimerInfo; t->dispatcher = this; t->timerId = timerId; @@ -1155,6 +1161,8 @@ void QEventDispatcherWin32::closingDown() d->timerVec.clear(); d->timerDict.clear(); + d->closingDown = true; + uninstallMessageHook(); } diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index a68f6cfa28..8022299a76 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -147,6 +147,7 @@ public: DWORD threadId; bool interrupt; + bool closingDown; // internal window handle used for socketnotifiers/timers/etc HWND internalHwnd; From aef2ed910861c732b401bcb17fe10dc9901c45bf Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 19 Nov 2014 09:11:56 +0100 Subject: [PATCH 300/323] Pick up QT_LOGGING_RULES also for bootstrapped tools Pick up logging rules set by QT_LOGGING_CONF, QT_LOGGING_RULES, and qtlogging.ini file also for bootstrapped tools. This helps e.g. in the case of winrtrunner, which uses categorized logging. Change-Id: I47d392137e17a59cb57b5c0226f282b0ccf29961 Reviewed-by: Oswald Buddenhagen Reviewed-by: Maurice Kalinowski --- src/corelib/kernel/qcoreapplication.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 45647f2056..77900ba906 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -714,9 +714,7 @@ void QCoreApplication::init() Q_ASSERT_X(!self, "QCoreApplication", "there should be only one application object"); QCoreApplication::self = this; -#ifndef QT_BOOTSTRAPPED QLoggingRegistry::instance()->init(); -#endif #ifndef QT_NO_QOBJECT // use the event dispatcher created by the app programmer (if any) From 94e40c7c7874a2bceb9d6f01947c1668fd92f559 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 18 Nov 2014 11:21:27 +0100 Subject: [PATCH 301/323] Observe QLocale::RejectGroupSeparator in QInt/DoubleValidator. Pass it as additional boolean parameter to QLocaleData::validateChars(). Task-number: QTBUG-42522 Change-Id: I4b2367f4e2fdcbd17e343d215edad57e6687697a Reviewed-by: Mitch Curtis --- src/corelib/tools/qlocale.cpp | 4 +-- src/corelib/tools/qlocale_p.h | 4 ++- src/gui/util/qvalidator.cpp | 10 ++++--- .../qdoublevalidator/tst_qdoublevalidator.cpp | 27 ++++++++++++------- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index a253057435..a923be50c0 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -3144,7 +3144,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, } bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArray *buff, - int decDigits) const + int decDigits, bool rejectGroupSeparators) const { buff->clear(); buff->reserve(str.length()); @@ -3205,7 +3205,7 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr case ',': //it can only be placed after a digit which is before the decimal point - if (!lastWasDigit || decPointCnt > 0) + if (rejectGroupSeparators || !lastWasDigit || decPointCnt > 0) return false; break; diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index c33ced35d5..c5e62027c4 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -251,7 +251,9 @@ public: inline char digitToCLocale(QChar c) const; // this function is used in QIntValidator (QtGui) - Q_CORE_EXPORT bool validateChars(const QString &str, NumberMode numMode, QByteArray *buff, int decDigits = -1) const; + Q_CORE_EXPORT bool validateChars(const QString &str, NumberMode numMode, + QByteArray *buff, int decDigits = -1, + bool rejectGroupSeparators = false) const; public: quint16 m_language_id, m_script_id, m_country_id; diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index aac9282710..f879847935 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -398,7 +398,8 @@ static qlonglong pow10(int exp) QValidator::State QIntValidator::validate(QString & input, int&) const { QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, + -1, locale().numberOptions() & QLocale::RejectGroupSeparator)) { return Invalid; } @@ -437,7 +438,8 @@ QValidator::State QIntValidator::validate(QString & input, int&) const void QIntValidator::fixup(QString &input) const { QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff)) { + if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, + -1, locale().numberOptions() & QLocale::RejectGroupSeparator)) { return; } bool ok, overflow; @@ -658,8 +660,10 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL { Q_Q(const QDoubleValidator); QByteArray buff; - if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec)) + if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec, + locale.numberOptions() & QLocale::RejectGroupSeparator)) { return QValidator::Invalid; + } if (buff.isEmpty()) return QValidator::Intermediate; diff --git a/tests/auto/gui/util/qdoublevalidator/tst_qdoublevalidator.cpp b/tests/auto/gui/util/qdoublevalidator/tst_qdoublevalidator.cpp index e08af2491d..a63183e5fc 100644 --- a/tests/auto/gui/util/qdoublevalidator/tst_qdoublevalidator.cpp +++ b/tests/auto/gui/util/qdoublevalidator/tst_qdoublevalidator.cpp @@ -59,30 +59,39 @@ void tst_QDoubleValidator::validateThouSep_data() { QTest::addColumn("localeName"); QTest::addColumn("value"); + QTest::addColumn("rejectGroupSeparator"); QTest::addColumn("result"); - QTest::newRow("1,000C") << "C" << QString("1,000") << ACC; - QTest::newRow("1.000C") << "C" << QString("1.000") << ACC; + QTest::newRow("1,000C") << "C" << QString("1,000") << false << ACC; + QTest::newRow("1,000.1C") << "C" << QString("1,000.1") << false << ACC; + QTest::newRow("1,000.1C_reject") << "C" << QString("1,000.1") << true << INV; + QTest::newRow("1.000C") << "C" << QString("1.000") << false << ACC; - QTest::newRow("1,000de") << "de" << QString("1,000") << ACC; - QTest::newRow("1.000de") << "de" << QString("1.000") << ACC; + QTest::newRow("1,000de") << "de" << QString("1,000") << false << ACC; + QTest::newRow("1.000de") << "de" << QString("1.000") << false << ACC; - QTest::newRow(".C") << "C" << QString(".") << ITM; - QTest::newRow(".de") << "de" << QString(".") << INV; - QTest::newRow(",C") << "C" << QString(",") << INV; - QTest::newRow(",de") << "de" << QString(",") << ITM; + QTest::newRow(".C") << "C" << QString(".") << false << ITM; + QTest::newRow(".de") << "de" << QString(".") << false << INV; + QTest::newRow("1.000,1de") << "de" << QString("1.000,1") << false << ACC; + QTest::newRow("1.000,1de_reject") << "de" << QString("1.000,1") << true << INV; + QTest::newRow(",C") << "C" << QString(",") << false << INV; + QTest::newRow(",de") << "de" << QString(",") << false << ITM; } void tst_QDoubleValidator::validateThouSep() { QFETCH(QString, localeName); QFETCH(QString, value); + QFETCH(bool, rejectGroupSeparator); QFETCH(QValidator::State, result); int dummy = 0; QDoubleValidator iv(-10000, 10000, 3, 0); iv.setNotation(QDoubleValidator::ScientificNotation); - iv.setLocale(QLocale(localeName)); + QLocale locale(localeName); + if (rejectGroupSeparator) + locale.setNumberOptions(QLocale::RejectGroupSeparator); + iv.setLocale(locale); QCOMPARE(iv.validate(value, dummy), result); } From 72278b7181383cfd8268b372860ab666d774bab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Mon, 17 Nov 2014 14:00:04 +0100 Subject: [PATCH 302/323] Do not skip the parent node when flattening the hierarchy. The weather app had a search field with a clear button as a child. Because of this bug it didn't report the content of the text edit (but only the clear button) Change-Id: I174c6e150e1991fa9aa2a911048590030b5ccc40 Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/ios/quiview_accessibility.mm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm index 6565e08302..74fb509b07 100644 --- a/src/plugins/platforms/ios/quiview_accessibility.mm +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -60,12 +60,9 @@ if (!iface) return; - if (iface->childCount() == 0) { - [self createAccessibleElement: iface]; - } else { - for (int i = 0; i < iface->childCount(); ++i) - [self createAccessibleContainer: iface->child(i)]; - } + [self createAccessibleElement: iface]; + for (int i = 0; i < iface->childCount(); ++i) + [self createAccessibleContainer: iface->child(i)]; } - (void)initAccessibility From f20af07e82f010273fd68b0545467c495e3c64f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Mon, 17 Nov 2014 14:38:18 +0100 Subject: [PATCH 303/323] Ignore nodes with no text name, value and description. This is in order to skip certain nodes that usually only carry structural information (such as ListItem nodes). However, because of the flattening, this structural information is never used on iOS, so we can just skip the accessible node completely. Change-Id: I17018c6565f8b39831f2d2944422c6670a438ab9 Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/ios/quiview_accessibility.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm index 74fb509b07..7e1cb9a4fd 100644 --- a/src/plugins/platforms/ios/quiview_accessibility.mm +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -48,7 +48,7 @@ - (void)createAccessibleElement:(QAccessibleInterface *)iface { - if (!iface || iface->state().invisible) + if (!iface || iface->state().invisible || (iface->text(QAccessible::Name).isEmpty() && iface->text(QAccessible::Value).isEmpty() && iface->text(QAccessible::Description).isEmpty())) return; QAccessible::Id accessibleId = QAccessible::uniqueId(iface); UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self]; From f217a8096b3c6188dd1d1520d854f330dbb17264 Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Thu, 13 Nov 2014 13:06:49 +1000 Subject: [PATCH 304/323] QtBearer networkmanager make sure to set flag Active Also, no need to create objects to get properties, when the properties can be had for free. Make plugin more robust to network-manager or ofono crashes Change-Id: Ibadb46bd51aa27f130f8d245e8c50aa7bff5f9c8 Reviewed-by: Alex Blasche Reviewed-by: Timo Jyrinki --- .../linux_common/qofonoservice_linux.cpp | 12 + .../linux_common/qofonoservice_linux_p.h | 2 + src/plugins/bearer/networkmanager/main.cpp | 5 +- .../networkmanager/qnetworkmanagerengine.cpp | 304 ++++++++++++------ .../networkmanager/qnetworkmanagerengine.h | 13 + .../networkmanager/qnetworkmanagerservice.cpp | 22 ++ .../networkmanager/qnetworkmanagerservice.h | 2 + 7 files changed, 260 insertions(+), 100 deletions(-) diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp index b2e2131a92..abbfd445a5 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux.cpp +++ b/src/plugins/bearer/linux_common/qofonoservice_linux.cpp @@ -269,6 +269,18 @@ QStringList QOfonoDataConnectionManagerInterface::contexts() return contextList; } +PathPropertiesList QOfonoDataConnectionManagerInterface::contextsWithProperties() +{ + if (contextListProperties.isEmpty()) { + QDBusPendingReply reply = call(QLatin1String("GetContexts")); + reply.waitForFinished(); + if (!reply.isError()) { + contextListProperties = reply.value(); + } + } + return contextListProperties; +} + bool QOfonoDataConnectionManagerInterface::roamingAllowed() { QVariant var = getProperty(QStringLiteral("RoamingAllowed")); diff --git a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h index 0ed00d94ff..3b97e06dd3 100644 --- a/src/plugins/bearer/linux_common/qofonoservice_linux_p.h +++ b/src/plugins/bearer/linux_common/qofonoservice_linux_p.h @@ -153,6 +153,7 @@ public: ~QOfonoDataConnectionManagerInterface(); QStringList contexts(); + PathPropertiesList contextsWithProperties(); bool roamingAllowed(); QVariant getProperty(const QString &); QString bearer(); @@ -162,6 +163,7 @@ private: QVariantMap getProperties(); QVariantMap propertiesMap; QStringList contextList; + PathPropertiesList contextListProperties; private slots: void propertyChanged(const QString &, const QDBusVariant &value); }; diff --git a/src/plugins/bearer/networkmanager/main.cpp b/src/plugins/bearer/networkmanager/main.cpp index f416bb42a6..3576ddc37c 100644 --- a/src/plugins/bearer/networkmanager/main.cpp +++ b/src/plugins/bearer/networkmanager/main.cpp @@ -66,10 +66,7 @@ QBearerEngine *QNetworkManagerEnginePlugin::create(const QString &key) const { if (key == QLatin1String("networkmanager")) { QNetworkManagerEngine *engine = new QNetworkManagerEngine; - if (engine->networkManagerAvailable()) - return engine; - else - delete engine; + return engine; } return 0; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp index a8244f05cf..f0977b4735 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -56,29 +56,34 @@ QT_BEGIN_NAMESPACE QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) : QBearerEngineImpl(parent), - managerInterface(new QNetworkManagerInterface(this)), - systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE, this)), - ofonoManager(new QOfonoManagerInterface(this)) + managerInterface(NULL), + systemSettings(NULL), + ofonoManager(NULL), + nmAvailable(false) { - - if (!managerInterface->isValid()) - return; - qDBusRegisterMetaType(); - connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), - this, SLOT(deviceAdded(QDBusObjectPath))); - connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), - this, SLOT(deviceRemoved(QDBusObjectPath))); - connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), - this, SLOT(activationFinished(QDBusPendingCallWatcher*))); - connect(managerInterface, SIGNAL(propertiesChanged(QMap)), - this, SLOT(interfacePropertiesChanged(QMap))); - managerInterface->setConnections(); + nmWatcher = new QDBusServiceWatcher(NM_DBUS_SERVICE,QDBusConnection::systemBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, this); + connect(nmWatcher, SIGNAL(serviceRegistered(QString)), + this, SLOT(nmRegistered(QString))); + connect(nmWatcher, SIGNAL(serviceUnregistered(QString)), + this, SLOT(nmUnRegistered(QString))); - connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), - this, SLOT(newConnection(QDBusObjectPath))); - systemSettings->setConnections(); + ofonoWatcher = new QDBusServiceWatcher("org.ofono",QDBusConnection::systemBus(), + QDBusServiceWatcher::WatchForRegistration | + QDBusServiceWatcher::WatchForUnregistration, this); + connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)), + this, SLOT(ofonoRegistered(QString))); + connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)), + this, SLOT(ofonoUnRegistered(QString))); + + if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.ofono")) + ofonoRegistered(); + + if (QDBusConnection::systemBus().interface()->isServiceRegistered(NM_DBUS_SERVICE)) + nmRegistered(); } QNetworkManagerEngine::~QNetworkManagerEngine() @@ -105,15 +110,13 @@ QNetworkManagerEngine::~QNetworkManagerEngine() void QNetworkManagerEngine::initialize() { - QMutexLocker locker(&mutex); + if (nmAvailable) + setupConfigurations(); +} - if (ofonoManager->isValid()) { - Q_FOREACH (const QString &modem, ofonoManager->getModems()) { - QOfonoDataConnectionManagerInterface *ofonoContextManager - = new QOfonoDataConnectionManagerInterface(modem,this); - ofonoContextManagers.insert(modem, ofonoContextManager); - } - } +void QNetworkManagerEngine::setupConfigurations() +{ + QMutexLocker locker(&mutex); // Get active connections. foreach (const QDBusObjectPath &acPath, managerInterface->activeConnections()) { @@ -151,7 +154,7 @@ void QNetworkManagerEngine::initialize() bool QNetworkManagerEngine::networkManagerAvailable() const { - return managerInterface->isValid(); + return nmAvailable; } QString QNetworkManagerEngine::getInterfaceFromId(const QString &settingsPath) @@ -180,6 +183,9 @@ void QNetworkManagerEngine::connectToId(const QString &id) const QString settingsPath = connection->connectionInterface()->path(); QString specificPath = configuredAccessPoints.key(settingsPath); + if (isConnectionActive(settingsPath)) + return; + QHashIterator i(interfaceDevices); while (i.hasNext()) { i.next(); @@ -229,7 +235,7 @@ void QNetworkManagerEngine::disconnectFromId(const QString &id) void QNetworkManagerEngine::requestUpdate() { - if (managerInterface->wirelessEnabled()) { + if (managerInterface && managerInterface->wirelessEnabled()) { QHashIterator i(wirelessDevices); while (i.hasNext()) { i.next(); @@ -282,8 +288,9 @@ void QNetworkManagerEngine::interfacePropertiesChanged(const QMapmutex.lock(); if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED && - ptr->state != QNetworkConfiguration::Active) { - ptr->state = QNetworkConfiguration::Active; + (ptr->state & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) { + + ptr->state |= QNetworkConfiguration::Active; if (activeConnectionsList.value(id) && activeConnectionsList.value(id)->defaultRoute() && managerInterface->state() < QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL) { @@ -339,23 +346,25 @@ void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMapmutex.lock(); - if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - QStringList devices = activeConnection->devices(); - if (!devices.isEmpty()) { - QNetworkManagerInterfaceDevice device(devices.at(0),this); - connectionInterfaces.insert(id,device.networkInterface()); + if (properties.contains(QStringLiteral("State"))) { + ptr->mutex.lock(); + if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + QStringList devices = activeConnection->devices(); + if (!devices.isEmpty()) { + QNetworkManagerInterfaceDevice device(devices.at(0),this); + connectionInterfaces.insert(id,device.networkInterface()); + } + + ptr->state |= QNetworkConfiguration::Active; + ptr->mutex.unlock(); + + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } else { + connectionInterfaces.remove(id); + ptr->mutex.unlock(); } - - ptr->state |= QNetworkConfiguration::Active; - ptr->mutex.unlock(); - - locker.unlock(); - emit configurationChanged(ptr); - locker.relock(); - } else { - connectionInterfaces.remove(id); - ptr->mutex.unlock(); } } } @@ -403,9 +412,6 @@ void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) connect(wirelessDevice,SIGNAL(scanDone()),this,SLOT(scanFinished())); wirelessDevice->setConnections(); - foreach (const QDBusObjectPath &apPath, wirelessDevice->getAccessPoints()) - newAccessPoint(apPath.path()); - wirelessDevices.insert(path.path(), wirelessDevice); } @@ -518,14 +524,9 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, parseConnection(settingsPath, connection->getSettings()); // Check if connection is active. - QHashIterator i(activeConnectionsList); - while (i.hasNext()) { - i.next(); - if (i.value()->connection().path() == settingsPath) { - cpPriv->state |= QNetworkConfiguration::Active; - break; - } - } + if (isConnectionActive(settingsPath)) + cpPriv->state |= QNetworkConfiguration::Active; + if (deviceType == DEVICE_TYPE_ETHERNET) { QHashIterator i(interfaceDevices); while (i.hasNext()) { @@ -539,12 +540,36 @@ void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, } } } + QNetworkConfigurationPrivatePointer ptr(cpPriv); accessPointConfigurations.insert(ptr->id, ptr); locker.unlock(); emit configurationAdded(ptr); } +bool QNetworkManagerEngine::isConnectionActive(const QString &settingsPath) +{ + QHashIterator i(activeConnectionsList); + while (i.hasNext()) { + i.next(); + if (i.value()->connection().path() == settingsPath) { + if (i.value()->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATING + || i.value()->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + return true; + } else { + break; + } + } + } + + QNetworkManagerSettingsConnection *settingsConnection = connectionFromId(settingsPath); + if (settingsConnection->getType() == DEVICE_TYPE_MODEM) { + return isActiveContext(settingsConnection->connectionInterface()->path()); + } + + return false; +} + void QNetworkManagerEngine::removeConnection(const QString &path) { QMutexLocker locker(&mutex); @@ -652,7 +677,6 @@ void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) void QNetworkManagerEngine::newAccessPoint(const QString &path) { QMutexLocker locker(&mutex); - QNetworkManagerInterfaceAccessPoint *accessPoint = new QNetworkManagerInterfaceAccessPoint(path,this); @@ -683,6 +707,9 @@ void QNetworkManagerEngine::newAccessPoint(const QString &path) ptr->mutex.lock(); QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined; ptr->state = (flag | QNetworkConfiguration::Discovered); + + if (isConnectionActive(settingsPath)) + ptr->state = (flag | QNetworkConfiguration::Active); ptr->mutex.unlock(); locker.unlock(); @@ -762,7 +789,6 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri QMutexLocker locker(&mutex); QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; cpPriv->name = map.value("connection").value("id").toString(); - cpPriv->isValid = true; cpPriv->id = settingsPath; cpPriv->type = QNetworkConfiguration::InternetAccessPoint; @@ -811,18 +837,46 @@ QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QStri } } else if (connectionType == QLatin1String("gsm")) { - const QString contextPath = map.value("connection").value("id").toString(); - cpPriv->name = contextName(contextPath); - cpPriv->bearerType = currentBearerType(contextPath); + const QString connectionPath = map.value("connection").value("id").toString(); + cpPriv->name = contextName(connectionPath); + cpPriv->bearerType = currentBearerType(connectionPath); - if (map.value("connection").contains("timestamp")) { - cpPriv->state |= QNetworkConfiguration::Discovered; + if (ofonoManager && ofonoManager->isValid()) { + const QString contextPart = connectionPath.section('/', -1); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + const QString path = i.key() +"/"+contextPart; + if (isActiveContext(path)) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } } } return cpPriv; } +bool QNetworkManagerEngine::isActiveContext(const QString &contextPath) +{ + if (ofonoManager && ofonoManager->isValid()) { + const QString contextPart = contextPath.section('/', -1); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + PathPropertiesList list = i.value()->contextsWithProperties(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).path.path().contains(contextPart)) { + return list.at(i).properties.value(QStringLiteral("Active")).toBool(); + + } + } + } + } + return false; +} + QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const { for (int i = 0; i < connections.count(); ++i) { @@ -967,53 +1021,111 @@ QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration( QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const QString &id) { - if (ofonoManager->isValid()) { - QString contextPart = id.section('/', -1); + QString contextPart = id.section('/', -1); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + QString contextPath = i.key() +"/"+contextPart; - QHashIterator i(ofonoContextManagers); - while (i.hasNext()) { - i.next(); - QString contextPath = i.key() +"/"+contextPart; - if (i.value()->contexts().contains(contextPath)) { + if (i.value()->contexts().contains(contextPath)) { - QString bearer = i.value()->bearer(); - if (bearer == QStringLiteral("gsm")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QStringLiteral("edge")) { - return QNetworkConfiguration::Bearer2G; - } else if (bearer == QStringLiteral("umts")) { - return QNetworkConfiguration::BearerWCDMA; - } else if (bearer == QStringLiteral("hspa") - || bearer == QStringLiteral("hsdpa") - || bearer == QStringLiteral("hsupa")) { - return QNetworkConfiguration::BearerHSPA; - } else if (bearer == QStringLiteral("lte")) { - return QNetworkConfiguration::BearerLTE; - } + QString bearer = i.value()->bearer(); + + if (bearer == QStringLiteral("gsm")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("edge")) { + return QNetworkConfiguration::Bearer2G; + } else if (bearer == QStringLiteral("umts")) { + return QNetworkConfiguration::BearerWCDMA; + } else if (bearer == QStringLiteral("hspa") + || bearer == QStringLiteral("hsdpa") + || bearer == QStringLiteral("hsupa")) { + return QNetworkConfiguration::BearerHSPA; + } else if (bearer == QStringLiteral("lte")) { + return QNetworkConfiguration::BearerLTE; } } } + return QNetworkConfiguration::BearerUnknown; } QString QNetworkManagerEngine::contextName(const QString &path) { - if (ofonoManager->isValid()) { - QString contextPart = path.section('/', -1); - QHashIterator i(ofonoContextManagers); - while (i.hasNext()) { - i.next(); - Q_FOREACH (const QString &oContext, i.value()->contexts()) { - if (oContext.contains(contextPart)) { - QOfonoConnectionContextInterface contextInterface(oContext,this); - return contextInterface.name(); - } + QString contextPart = path.section('/', -1); + QHashIterator i(ofonoContextManagers); + while (i.hasNext()) { + i.next(); + PathPropertiesList list = i.value()->contextsWithProperties(); + for (int i = 0; i < list.size(); ++i) { + if (list.at(i).path.path().contains(contextPart)) { + return list.at(i).properties.value(QStringLiteral("Name")).toString(); } } } return path; } +void QNetworkManagerEngine::nmRegistered(const QString &) +{ + if (ofonoManager) { + delete ofonoManager; + ofonoManager = NULL; + } + managerInterface = new QNetworkManagerInterface(this); + systemSettings = new QNetworkManagerSettings(NM_DBUS_SERVICE, this); + + connect(managerInterface, SIGNAL(deviceAdded(QDBusObjectPath)), + this, SLOT(deviceAdded(QDBusObjectPath))); + connect(managerInterface, SIGNAL(deviceRemoved(QDBusObjectPath)), + this, SLOT(deviceRemoved(QDBusObjectPath))); + connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), + this, SLOT(activationFinished(QDBusPendingCallWatcher*))); + connect(managerInterface, SIGNAL(propertiesChanged(QMap)), + this, SLOT(interfacePropertiesChanged(QMap))); + managerInterface->setConnections(); + + connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); + systemSettings->setConnections(); + nmAvailable = true; + + setupConfigurations(); +} + +void QNetworkManagerEngine::nmUnRegistered(const QString &) +{ + if (systemSettings) { + delete systemSettings; + systemSettings = NULL; + } + if (managerInterface) { + delete managerInterface; + managerInterface = NULL; + } +} + +void QNetworkManagerEngine::ofonoRegistered(const QString &) +{ + if (ofonoManager) { + delete ofonoManager; + ofonoManager = NULL; + } + ofonoManager = new QOfonoManagerInterface(this); + if (ofonoManager && ofonoManager->isValid()) { + Q_FOREACH (const QString &modem, ofonoManager->getModems()) { + QOfonoDataConnectionManagerInterface *ofonoContextManager + = new QOfonoDataConnectionManagerInterface(modem,this); + ofonoContextManagers.insert(modem, ofonoContextManager); + } + } +} + +void QNetworkManagerEngine::ofonoUnRegistered(const QString &) +{ + ofonoContextManagers.clear(); +} + QT_END_NAMESPACE #endif // QT_NO_DBUS diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h index 671ed80dab..da6af14c00 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.h @@ -109,6 +109,12 @@ private Q_SLOTS: void wiredCarrierChanged(bool); + void nmRegistered(const QString &serviceName = QString()); + void nmUnRegistered(const QString &serviceName = QString()); + + void ofonoRegistered(const QString &serviceName = QString()); + void ofonoUnRegistered(const QString &serviceName = QString()); + private: QNetworkConfigurationPrivate *parseConnection(const QString &settingsPath, const QNmSettingsMap &map); @@ -132,6 +138,13 @@ private: QNetworkConfiguration::BearerType currentBearerType(const QString &id); QString contextName(const QString &path); + bool isConnectionActive(const QString &settingsPath); + QDBusServiceWatcher *ofonoWatcher; + QDBusServiceWatcher *nmWatcher; + + bool isActiveContext(const QString &contextPath); + bool nmAvailable; + void setupConfigurations(); }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp index dc3b71ec8e..fad94f069d 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.cpp @@ -688,6 +688,15 @@ QNetworkManagerInterfaceDeviceWireless::QNetworkManagerInterfaceDeviceWireless(c QLatin1String(NM_DBUS_INTERFACE_DEVICE_WIRELESS), QLatin1String("PropertiesChanged"), this,SLOT(propertiesSwap(QMap))); + + QDBusPendingReply > reply + = d->connectionInterface->asyncCall(QLatin1String("GetAccessPoints")); + + QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(reply); + connect(callWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(accessPointsFinished(QDBusPendingCallWatcher*))); + + d->valid = true; } @@ -749,6 +758,19 @@ bool QNetworkManagerInterfaceDeviceWireless::setConnections() return allOk; } +void QNetworkManagerInterfaceDeviceWireless::accessPointsFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply > reply(*watcher); + watcher->deleteLater(); + if (!reply.isError()) { + accessPointsList = reply.value(); + } + + for (int i = 0; i < accessPointsList.size(); i++) { + Q_EMIT accessPointAdded(accessPointsList.at(i).path()); + } +} + QDBusInterface *QNetworkManagerInterfaceDeviceWireless::connectionInterface() const { return d->connectionInterface; diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h index da909c443a..e645159d71 100644 --- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h @@ -369,6 +369,8 @@ private Q_SLOTS: void slotAccessPointAdded(QDBusObjectPath); void slotAccessPointRemoved(QDBusObjectPath); + void accessPointsFinished(QDBusPendingCallWatcher *watcher); + private: QNetworkManagerInterfaceDeviceWirelessPrivate *d; QVariantMap propertyMap; From 6c5d1dbd75f4edf886420cb07efeb1c20a1b0bbf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 18 Nov 2014 17:10:33 +0100 Subject: [PATCH 305/323] Fix widget leak in tst_qmainwindow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-38152 Change-Id: I4cf94a4a8977019dcfc099966643b5b036cc1021 Reviewed-by: Jan Arve Sæther --- .../auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp index 27c803b43d..751a16c59d 100644 --- a/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp +++ b/tests/auto/widgets/widgets/qmainwindow/tst_qmainwindow.cpp @@ -104,6 +104,7 @@ public: tst_QMainWindow(); private slots: + void cleanup(); void getSetCheck(); void constructor(); void iconSize(); @@ -147,6 +148,12 @@ private slots: void QTBUG21378_animationFinished(); }; + +void tst_QMainWindow::cleanup() +{ + QVERIFY(QApplication::topLevelWidgets().isEmpty()); +} + // Testing get/set functions void tst_QMainWindow::getSetCheck() { @@ -854,6 +861,7 @@ void tst_QMainWindow::takeCentralWidget() { QVERIFY(!w2.isNull()); QCOMPARE(w2.data(), hopefullyW2); + delete w2; } void tst_QMainWindow::corner() From eb466b636b97251d273aedddfe66b15fe994d375 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 17 Nov 2014 18:35:52 +0100 Subject: [PATCH 306/323] Fix QAction::setFont crash on OSX, when font is unknown. customMenuFont was null, so objects was an empty array, and NSDictionary throws an exception when being called with arrays of different sizes. Task-number: QTBUG-42728 Change-Id: I8cdab449fd8c1d12b65c46dd5617a7f5e3e96c6e Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoamenuitem.mm | 19 ++++++++++++------- .../widgets/kernel/qaction/tst_qaction.cpp | 10 ++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 791b0805d0..251fe9485c 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -323,17 +323,22 @@ NSMenuItem *QCocoaMenuItem::sync() text += QLatin1String(" (") + accel.toString(QKeySequence::NativeText) + QLatin1String(")"); QString finalString = qt_mac_removeMnemonics(text); + bool useAttributedTitle = false; // Cocoa Font and title if (m_font.resolve()) { NSFont *customMenuFont = [NSFont fontWithName:QCFString::toNSString(m_font.family()) size:m_font.pointSize()]; - NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil]; - NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil]; - NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; - NSAttributedString *str = [[[NSAttributedString alloc] initWithString:QCFString::toNSString(finalString) - attributes:attributes] autorelease]; - [m_native setAttributedTitle: str]; - } else { + if (customMenuFont) { + NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil]; + NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil]; + NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys]; + NSAttributedString *str = [[[NSAttributedString alloc] initWithString:QCFString::toNSString(finalString) + attributes:attributes] autorelease]; + [m_native setAttributedTitle: str]; + useAttributedTitle = true; + } + } + if (!useAttributedTitle) { [m_native setTitle: QCFString::toNSString(finalString)]; } diff --git a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp index 7904848faf..4b7e2a7198 100644 --- a/tests/auto/widgets/kernel/qaction/tst_qaction.cpp +++ b/tests/auto/widgets/kernel/qaction/tst_qaction.cpp @@ -61,6 +61,7 @@ private slots: void setText(); void setIconText_data() { setText_data(); } void setIconText(); + void setUnknownFont(); void actionEvent(); void setStandardKeys(); void alternateShortcuts(); @@ -184,6 +185,15 @@ void tst_QAction::setIconText() QCOMPARE(action.text(), textFromIconText); } +void tst_QAction::setUnknownFont() // QTBUG-42728 +{ + QAction action(0); + QFont font("DoesNotExist", 11); + action.setFont(font); + + QMenu menu; + menu.addAction(&action); // should not crash +} void tst_QAction::updateState(QActionEvent *e) { From cd75ca0dbd2b9b6cef8fd840f3ecdeeb04502362 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 19 Nov 2014 14:21:40 +0100 Subject: [PATCH 307/323] WinRT: Ignore winrtrunner specific arguments qdevel is an option used from winrtrunner to indicate a specific environment to the app. QTestLib needs to ignore that parameter similar to the Visual Studio generated arguments. Change-Id: I00a3abe19f1e5b4159e65d26050f04e28f40316f Reviewed-by: Oliver Wolff Reviewed-by: Andrew Knight --- src/testlib/qtestcase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index b174913eae..928a3f31f1 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1728,7 +1728,8 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, char *argv[], bool qml) } else if (strcmp(argv[i], "-vb") == 0) { QBenchmarkGlobalData::current->verboseOutput = true; #ifdef Q_OS_WINRT - } else if (strncmp(argv[i], "-ServerName:", 12) == 0) { + } else if (strncmp(argv[i], "-ServerName:", 12) == 0 || + strncmp(argv[i], "-qdevel", 7) == 0) { continue; #endif } else if (argv[i][0] == '-') { From a2f78ea0a147301222cb5346fad7e09121d87d59 Mon Sep 17 00:00:00 2001 From: Jan-Marek Glogowski Date: Tue, 11 Mar 2014 15:14:16 +0100 Subject: [PATCH 308/323] Fix tst_QEventLoop::processEventsExcludeSocket test The testcase always returns the expected result, independently of the QEventLoop::ExcludeSocketNotifiers flag to processEvents. In Qt4 the same test uses an intermediate QEventLoop and already runs it before the QEventLoop::ExcludeSocketNotifiers: QEventLoop loop; // allow the TCP/IP stack time to loopback the data, // so our socket is ready to read QTimer::singleShot(200, &loop, SLOT(quit())); loop.exec(QEventLoop::ExcludeSocketNotifiers); This fixes and improves the test by connecting, processing and checking the bytesWritten signal for the pending connection socket. Change-Id: I1b1d2b7b83910c87ba3fe48e29ac9fd585ac62ad Reviewed-by: Thiago Macieira --- .../kernel/qeventloop/tst_qeventloop.cpp | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp index 5cfbce0d7a..befd45018a 100644 --- a/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/corelib/kernel/qeventloop/tst_qeventloop.cpp @@ -40,6 +40,7 @@ #include #if defined(Q_OS_UNIX) #include + #include #if defined(HAVE_GLIB) #include #endif @@ -172,7 +173,9 @@ private slots: void execAfterExit(); void wakeUp(); void quit(); +#if defined(Q_OS_UNIX) void processEventsExcludeSocket(); +#endif void processEventsExcludeTimers(); void deliverInDefinedOrder(); @@ -383,6 +386,7 @@ void tst_QEventLoop::customEvent(QEvent *e) } } +#if defined(Q_OS_UNIX) class SocketEventsTester: public QObject { Q_OBJECT @@ -391,8 +395,10 @@ public: { socket = 0; server = 0; - dataArrived = false; + dataSent = false; + dataReadable = false; testResult = false; + dataArrived = false; } ~SocketEventsTester() { @@ -415,8 +421,10 @@ public: QTcpSocket *socket; QTcpServer *server; - bool dataArrived; + bool dataSent; + bool dataReadable; bool testResult; + bool dataArrived; public slots: void sendAck() { @@ -428,12 +436,26 @@ public slots: qint64 size = sizeof(data); QTcpSocket *serverSocket = server->nextPendingConnection(); + QCoreApplication::processEvents(); serverSocket->write(data, size); - serverSocket->flush(); - QTest::qSleep(200); //allow the TCP/IP stack time to loopback the data, so our socket is ready to read - QCoreApplication::processEvents(QEventLoop::ExcludeSocketNotifiers); - testResult = dataArrived; - QCoreApplication::processEvents(); //check the deferred event is processed + dataSent = serverSocket->waitForBytesWritten(-1); + + if (dataSent) { + fd_set fdread; + int fd = socket->socketDescriptor(); + FD_ZERO(&fdread); + FD_SET(fd, &fdread); + dataReadable = (1 == qt_safe_select(fd + 1, &fdread, 0, 0, 0)); + } + + if (!dataReadable) { + testResult = dataArrived; + } else { + QCoreApplication::processEvents(QEventLoop::ExcludeSocketNotifiers); + testResult = dataArrived; + // to check if the deferred event is processed + QCoreApplication::processEvents(); + } serverSocket->close(); QThread::currentThread()->exit(0); } @@ -449,12 +471,16 @@ public: SocketEventsTester *tester = new SocketEventsTester(); if (tester->init()) exec(); + dataSent = tester->dataSent; + dataReadable = tester->dataReadable; testResult = tester->testResult; dataArrived = tester->dataArrived; delete tester; } - bool testResult; - bool dataArrived; + bool dataSent; + bool dataReadable; + bool testResult; + bool dataArrived; }; void tst_QEventLoop::processEventsExcludeSocket() @@ -462,9 +488,17 @@ void tst_QEventLoop::processEventsExcludeSocket() SocketTestThread thread; thread.start(); QVERIFY(thread.wait()); + QVERIFY(thread.dataSent); + QVERIFY(thread.dataReadable); + #if defined(HAVE_GLIB) + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + if (qobject_cast(eventDispatcher)) + QEXPECT_FAIL("", "ExcludeSocketNotifiers is currently broken in the Glib dispatchers", Continue); + #endif QVERIFY(!thread.testResult); QVERIFY(thread.dataArrived); } +#endif class TimerReceiver : public QObject { From 9bb64bff6139b63e271dca53f1be34b277436b65 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 18 Nov 2014 17:15:59 -0800 Subject: [PATCH 309/323] Fix coding style in QtCore Never start a line with a comma. Change-Id: Idce1766f2661aa97fd163c02436ef315999985ec Reviewed-by: Konstantin Ritt Reviewed-by: Lars Knoll --- src/corelib/tools/qelapsedtimer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qelapsedtimer.h b/src/corelib/tools/qelapsedtimer.h index d72a50f127..d21081f815 100644 --- a/src/corelib/tools/qelapsedtimer.h +++ b/src/corelib/tools/qelapsedtimer.h @@ -51,8 +51,8 @@ public: }; Q_DECL_CONSTEXPR QElapsedTimer() - : t1(Q_INT64_C(0x8000000000000000)) - , t2(Q_INT64_C(0x8000000000000000)) + : t1(Q_INT64_C(0x8000000000000000)), + t2(Q_INT64_C(0x8000000000000000)) { } From def272750cdb7810bca4f4815ed1183ba2bd6df9 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 19 Nov 2014 11:12:32 -0800 Subject: [PATCH 310/323] Put parentheses around "min" to prevent expansion as macro If you write xxxx::min(), min() might be expanded as a macro on silly environments that follow that poor practice (read: inclusion of without NOMINMAX). However, if you write (min)() or (xxx::min)(), it means the same but prevents the expansion as macro. Task-number: QTBUG-42767 Task-number: QTBUG-31469 Change-Id: If3c93aafd4d0bf63ca15f3d01c2297d58d00f6bc Reviewed-by: Oswald Buddenhagen --- src/corelib/tools/qdatetime.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index c5e64d7d52..a75d7d9bc8 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -111,7 +111,8 @@ QT_DEPRECATED inline bool setYMD(int y, int m, int d) inline qint64 toJulianDay() const { return jd; } private: - static inline qint64 nullJd() { return std::numeric_limits::min(); } + // using extra parentheses around min to avoid expanding it if it is a macro + static inline qint64 nullJd() { return (std::numeric_limits::min)(); } static inline qint64 minJd() { return Q_INT64_C(-784350574879); } static inline qint64 maxJd() { return Q_INT64_C( 784354017364); } From 49052ba8a87fc0f8dc437d63cc541845501ab7a8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 18 Nov 2014 22:11:48 -0800 Subject: [PATCH 311/323] QtTest: fix pretty-printing of QStrings containing " It needs to be escaped with a backslash. Change-Id: Idf62914fca08eb6be8a039c2af72bac42c0d594a Reviewed-by: Jason McDonald --- src/testlib/qtestcase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 928a3f31f1..24d563045b 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2153,7 +2153,7 @@ char *toPrettyUnicode(const ushort *p, int length) break; } - if (*p < 0x7f && *p >= 0x20 && *p != '\\') { + if (*p < 0x7f && *p >= 0x20 && *p != '\\' && *p != '"') { *dst++ = *p; continue; } From cd2ac1e2e54b2bdd3b539ac29eb461911d4b6314 Mon Sep 17 00:00:00 2001 From: Matt Fischer Date: Thu, 16 Oct 2014 17:04:11 -0500 Subject: [PATCH 312/323] Don't send reply messages for non-method calls in QDBusMessage QDBusMessage is intended to avoid sending reply messages unless the message is a method call without the NO_REPLY_EXPECTED flag set. However, since messages which are not method calls will never have this flag set, the code will currently cause all non-method call messages to expect a reply. This patch changes the code to examine the message type, and to only check for the flag in cases where the message is a method call. Change-Id: Ic5bb00df69d3cfb38f60bf6bfd8463fb28cf2c99 Reviewed-by: Thiago Macieira --- src/dbus/qdbusmessage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp index 8025636668..25206b4bb7 100644 --- a/src/dbus/qdbusmessage.cpp +++ b/src/dbus/qdbusmessage.cpp @@ -605,6 +605,10 @@ QString QDBusMessage::signature() const */ bool QDBusMessage::isReplyRequired() const { + // Only method calls can have replies + if (d_ptr->type != DBUS_MESSAGE_TYPE_METHOD_CALL) + return false; + if (!d_ptr->msg) return d_ptr->localMessage; // if it's a local message, reply is required return !q_dbus_message_get_no_reply(d_ptr->msg); From 749f4f0e55bc3864add3c25de00b9ccf2f8c8c6c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 26 Aug 2014 12:00:30 -0700 Subject: [PATCH 313/323] Disable the tests that verify that the available space shrunk Somehow, it doesn't shrink with btrfs, even if you write 1 MB of non- null data. This does not seem to be a bug in QStorageInfo. strace confirms that there is a second statvfs call happening. Change-Id: I9ed99d27d25e191916278e6b8faeae132469fc63 Reviewed-by: Oswald Buddenhagen --- .../auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp b/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp index e07dda250f..3abbb71960 100644 --- a/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp +++ b/tests/auto/corelib/io/qstorageinfo/tst_qstorageinfo.cpp @@ -154,6 +154,11 @@ void tst_QStorageInfo::tempFile() QVERIFY(file.open()); QStorageInfo storage1(file.fileName()); +#ifdef Q_OS_LINUX + if (storage1.fileSystemType() == "btrfs") + QSKIP("This test doesn't work on btrfs, probably due to a btrfs bug"); +#endif + qint64 free = storage1.bytesFree(); file.write(QByteArray(1024*1024, '1')); @@ -170,6 +175,11 @@ void tst_QStorageInfo::caching() QVERIFY(file.open()); QStorageInfo storage1(file.fileName()); +#ifdef Q_OS_LINUX + if (storage1.fileSystemType() == "btrfs") + QSKIP("This test doesn't work on btrfs, probably due to a btrfs bug"); +#endif + qint64 free = storage1.bytesFree(); QStorageInfo storage2(storage1); QVERIFY(free == storage2.bytesFree()); From 32b7eb8e986b8e30fe68d91c7a30bbc5a95593bd Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 29 Oct 2014 17:10:41 -0700 Subject: [PATCH 314/323] Work around ICC compatibility problem with Apple headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apple uses __OSX_AVAILABLE_STARTING in enum values too, which ICC doesn't like. We need to force at least OS X 10.9 so we don't run into build errors. FSEvents.h(279): error: expected a "}" kFSEventStreamCreateFlagMarkSelf __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) = 0x00000020 ^ Intel issue ID: 6000071924 Change-Id: Iae1abb8e8e92f228571c5064d96e9d33d3e35173 Reviewed-by: Oswald Buddenhagen Reviewed-by: Tor Arne Vestbø Reviewed-by: Thiago Macieira --- mkspecs/macx-icc/qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/macx-icc/qmake.conf b/mkspecs/macx-icc/qmake.conf index 09994b639f..5e45e67d0c 100644 --- a/mkspecs/macx-icc/qmake.conf +++ b/mkspecs/macx-icc/qmake.conf @@ -84,7 +84,7 @@ QMAKE_CXXFLAGS_PRECOMPILE = -c -pch-create ${QMAKE_PCH_OUTPUT} -include ${QMAKE_ QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden -QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 +QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.9 include(../common/macx.conf) From c6e21eb673a7c3e4abcf90bd3bad1ec0890d6b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Klitzing?= Date: Fri, 14 Nov 2014 18:01:17 +0100 Subject: [PATCH 315/323] SSL: Fix sslConfiguration in encrypted slot If "encrypted" signal is fired the configuration of ssl is not updated. If someone wants to perform additional checks on the certificate chain it is now possible to use peerCertificate and peerCertificateChain. Change-Id: Id5136a8c52727562c36028eaef721cc9ad86619d Task-number: QTBUG-40401 Reviewed-by: Richard J. Moore --- src/network/access/qhttpthreaddelegate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 524042add6..4e1d24280b 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -644,6 +644,7 @@ void QHttpThreadDelegate::encryptedSlot() if (!httpReply) return; + emit sslConfigurationChanged(httpReply->sslConfiguration()); emit encrypted(); } From 4fec31dcc003ccd107b447b2ee86dab1eedae642 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 22 Nov 2014 17:09:08 -0800 Subject: [PATCH 316/323] Fix failure to build QtQuick with LTO The presence of the inline QTestFontEngine's constructor causes a linker failure because QFontEngineBox isn't exported. I'd say this is a compiler bug (GCC 4.9), but it's an easy workaround and a difficult testcase. typeinfo for QTestFontEngine: error: undefined reference to 'typeinfo for QFontEngineBox' vtable for QTestFontEngine: error: undefined reference to 'QFontEngineBox::glyphIndex(unsigned int) const' Change-Id: I84829d111616977d6f3fcbbb48509d1c7d4f5fa6 Reviewed-by: Konstantin Ritt --- src/gui/text/qfontengine.cpp | 4 ++++ src/gui/text/qfontengine_p.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 0b517fbf29..b2a7a8e91f 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -2105,4 +2105,8 @@ QFontEngine* QFontEngineMultiBasicImpl::createMultiFontEngine(QFontEngine *fe, i return engine; } +QTestFontEngine::QTestFontEngine(int size) + : QFontEngineBox(TestFontEngine, size) +{} + QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 50b1bb9e9d..9364b82bed 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -463,7 +463,7 @@ private: class QTestFontEngine : public QFontEngineBox { public: - inline QTestFontEngine(int size) : QFontEngineBox(TestFontEngine, size) {} + QTestFontEngine(int size); }; QT_END_NAMESPACE From 13b939c7f41bceb2061e549923eab242326e9bb5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 22 Nov 2014 16:49:11 -0800 Subject: [PATCH 317/323] Fix warning about QDeviceDiscovery violating ODR rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compiling with GCC 4.9's LTO, the compiler realizes that the class looks different in two different compilation units and prints a warning. Adding the necessary #define will make sure that the warning isn't printed. It's possible the warning indicates a real problem, if the class actually got used in those two plugins. I wouldn't know. QtPlatformSupport/private/.../qdevicediscovery_p.h:66:7: warning: type ‘struct QDeviceDiscovery’ violates one definition rule .moc/.../qdevicediscovery_p.h:66:7: note: a type with the same name but different layout is defined in another translation unit Change-Id: I73ca8e553e392b8d368f0deaa318d3e6635d73e1 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/directfb/directfb.pro | 2 ++ src/plugins/platforms/kms/kms.pro | 1 + src/plugins/platforms/linuxfb/linuxfb.pro | 1 + 3 files changed, 4 insertions(+) diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index 89d8d42cea..13481f6198 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -29,6 +29,8 @@ HEADERS = qdirectfbintegration.h \ qdirectfbscreen.h \ qdirectfbeglhooks.h +contains(QT_CONFIG, libudev): DEFINES += QDEVICEDISCOVERY_UDEV + # ### port the GL context contains(QT_CONFIG, directfb_egl) { HEADERS += qdirectfb_egl.h diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index baa8778153..948d986fc5 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -9,6 +9,7 @@ QT += core-private gui-private platformsupport-private qtHaveModule(opengl):QT += opengl-private DEFINES += MESA_EGL_NO_X11_HEADERS __GBM__ +contains(QT_CONFIG, libudev): DEFINES += QDEVICEDISCOVERY_UDEV CONFIG += link_pkgconfig egl qpa/genericunixfontdatabase diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index 389d45c29c..5e185e357f 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -9,6 +9,7 @@ QT += core-private gui-private platformsupport-private SOURCES = main.cpp qlinuxfbintegration.cpp qlinuxfbscreen.cpp HEADERS = qlinuxfbintegration.h qlinuxfbscreen.h +contains(QT_CONFIG, libudev): DEFINES += QDEVICEDISCOVERY_UDEV CONFIG += qpa/genericunixfontdatabase From 5f6284a98baded49d31b9723117a98d3bd010cfe Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Sun, 23 Nov 2014 01:00:05 +0100 Subject: [PATCH 318/323] Implement Download folder path retrieval on OS X The current implementation returns the DocumentLocation folder. Since now only cocoa is supported, we can use NSFileManager to get the correct path. [ChangeLog][QtCore][OS X] Now QStandardPaths returns the correct path for the DownloadLocation. Change-Id: Ic0ea3ebf8585a1e34a7b43c734df78fd3949d4d4 Reviewed-by: Thiago Macieira --- src/corelib/io/io.pri | 5 ++--- src/corelib/io/qstandardpaths.cpp | 2 +- ...{qstandardpaths_mac.cpp => qstandardpaths_mac.mm} | 12 ++++++++++-- src/tools/bootstrap/bootstrap.pro | 7 ++++--- 4 files changed, 17 insertions(+), 9 deletions(-) rename src/corelib/io/{qstandardpaths_mac.cpp => qstandardpaths_mac.mm} (94%) diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index bdc362ef22..77788e3cca 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -148,9 +148,8 @@ win32 { HEADERS += io/qfilesystemwatcher_fsevents_p.h } macx { - SOURCES += \ - io/qstorageinfo_mac.cpp \ - io/qstandardpaths_mac.cpp + SOURCES += io/qstorageinfo_mac.cpp + OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm LIBS += -framework DiskArbitration -framework IOKit } else:ios { OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index c206e432f6..6950d58fda 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -195,7 +195,7 @@ QT_BEGIN_NAMESPACE \li "~/Library/Preferences" \li "C:/Users//AppData/Local", "C:/ProgramData" \row \li DownloadLocation - \li "~/Documents" + \li "~/Downloads" \li "C:/Users//Documents" \row \li GenericCacheLocation \li "~/Library/Caches", "/Library/Caches" diff --git a/src/corelib/io/qstandardpaths_mac.cpp b/src/corelib/io/qstandardpaths_mac.mm similarity index 94% rename from src/corelib/io/qstandardpaths_mac.cpp rename to src/corelib/io/qstandardpaths_mac.mm index 673b734d40..01d1c01f78 100644 --- a/src/corelib/io/qstandardpaths_mac.cpp +++ b/src/corelib/io/qstandardpaths_mac.mm @@ -33,6 +33,7 @@ #include "qstandardpaths.h" #include +#include #include #ifndef QT_BOOTSTRAPPED @@ -55,8 +56,6 @@ OSType translateLocation(QStandardPaths::StandardLocation type) return kPreferencesFolderType; case QStandardPaths::DesktopLocation: return kDesktopFolderType; - case QStandardPaths::DownloadLocation: // needs NSSearchPathForDirectoriesInDomains with NSDownloadsDirectory - // which needs an objective-C *.mm file... case QStandardPaths::DocumentsLocation: return kDocumentsFolderType; case QStandardPaths::FontsLocation: @@ -113,6 +112,15 @@ static void appendOrganizationAndApp(QString &path) static QString macLocation(QStandardPaths::StandardLocation type, short domain) { + // https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSFileManager_Class/index.html + if (type == QStandardPaths::DownloadLocation) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *url = [fileManager URLForDirectory:NSDownloadsDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; + if (!url) + return QString(); + return QString::fromNSString([url path]); + } + // http://developer.apple.com/documentation/Carbon/Reference/Folder_Manager/Reference/reference.html FSRef ref; OSErr err = FSFindFolder(domain, translateLocation(type), false, &ref); diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro index 2b58bff8f3..527a932c4d 100644 --- a/src/tools/bootstrap/bootstrap.pro +++ b/src/tools/bootstrap/bootstrap.pro @@ -132,12 +132,13 @@ win32:SOURCES += ../../corelib/io/qfilesystemengine_win.cpp \ mac { SOURCES += ../../corelib/kernel/qcoreapplication_mac.cpp \ ../../corelib/kernel/qcore_mac.cpp - LIBS += -framework CoreServices + LIBS += -framework CoreServices -framework Foundation } macx { - SOURCES += \ - ../../corelib/io/qstandardpaths_mac.cpp + OBJECTIVE_SOURCES += \ + ../../corelib/tools/qstring_mac.mm \ + ../../corelib/io/qstandardpaths_mac.mm } else:unix { SOURCES += \ ../../corelib/io/qstandardpaths_unix.cpp From edd436a268ea038322735174fddb6da3a29d147d Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 20 Nov 2014 10:15:23 +0100 Subject: [PATCH 319/323] OSX: implement QFontMetrics::maxWidth(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CoreText doesn't seem to provide us with a "maximum advance" value, but 0 is really wrong, it leads to QLineEdit::minimumSizeHint() being 0 since it's based on maxWidth(). It even led to a negative min width with setTextMargins(-1, 0, -1, 0). Change-Id: I4faf8ecfb6d91e9dff66ec63651d003014503cb4 Reviewed-by: Konstantin Ritt Reviewed-by: Tor Arne Vestbø --- .../fontdatabases/mac/qfontengine_coretext.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 2859886d59..23fe48b493 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -353,7 +353,10 @@ QFixed QCoreTextFontEngine::averageCharWidth() const qreal QCoreTextFontEngine::maxCharWidth() const { - return 0; + // ### FIXME: 'W' might not be the widest character, but this is better than nothing + const glyph_t glyph = glyphIndex('W'); + glyph_metrics_t bb = const_cast(this)->boundingBox(glyph); + return bb.xoff.toReal(); } qreal QCoreTextFontEngine::minLeftBearing() const From dcbf704bc0f3e7cdedb5c0839575a7f9546fc245 Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 18 Nov 2014 21:34:58 +0100 Subject: [PATCH 320/323] tst_qtableview: fix virtual-override clang warning Change-Id: I40391890c988ce15d8fa65898976bf0fdc446992 Reviewed-by: Friedemann Kleint --- tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index 565eac2cba..389ff6572d 100644 --- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -434,7 +434,7 @@ public: { QTableView::setModel(model); connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(currentChanged(QModelIndex,QModelIndex))); + this, SLOT(slotCurrentChanged(QModelIndex,QModelIndex))); connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(itemSelectionChanged(QItemSelection,QItemSelection))); } @@ -495,7 +495,7 @@ public: bool checkSignalOrder; public slots: - void currentChanged(QModelIndex , QModelIndex ) { + void slotCurrentChanged(QModelIndex, QModelIndex) { hasCurrentChanged++; if (checkSignalOrder) QVERIFY(hasCurrentChanged > hasSelectionChanged); From 736ac191565196514e14f875c774771026f95d7e Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 18 Nov 2014 21:47:41 +0100 Subject: [PATCH 321/323] QAbstractProxyModel: fix canDropMimeData/dropMimeData implementations The code in 4696e9dbaa4 was incorrect. It is perfectly valid to call these methods with row=-1 column=1 parent=some_index, this is exactly what happens in QListView and QTableView. Child row/column is only for trees. Move the coordinate mapping from QSortFilterProxyModel into a new mapDropCoordinatesToSource internal method, used by QAbstractProxyModel. Task-number: QTBUG-39549 Change-Id: I3312210473d84b639cbe4c01f70ea36437db3e91 Reviewed-by: Friedemann Kleint Reviewed-by: Stephen Kelly --- .../itemmodels/qabstractproxymodel.cpp | 34 +++++++++-- .../itemmodels/qabstractproxymodel_p.h | 2 + .../itemmodels/qsortfilterproxymodel.cpp | 20 +------ .../tst_qsortfilterproxymodel.cpp | 56 +++++++++++++++++++ 4 files changed, 90 insertions(+), 22 deletions(-) diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp index ce26293183..b7f988ef7c 100644 --- a/src/corelib/itemmodels/qabstractproxymodel.cpp +++ b/src/corelib/itemmodels/qabstractproxymodel.cpp @@ -384,6 +384,26 @@ QMimeData* QAbstractProxyModel::mimeData(const QModelIndexList &indexes) const return d->model->mimeData(list); } +void QAbstractProxyModelPrivate::mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent, + int *sourceRow, int *sourceColumn, QModelIndex *sourceParent) const +{ + Q_Q(const QAbstractProxyModel); + *sourceRow = -1; + *sourceColumn = -1; + if (row == -1 && column == -1) { + *sourceParent = q->mapToSource(parent); + } else if (row == q->rowCount(parent)) { + *sourceParent = q->mapToSource(parent); + *sourceRow = model->rowCount(*sourceParent); + } else { + QModelIndex proxyIndex = q->index(row, column, parent); + QModelIndex sourceIndex = q->mapToSource(proxyIndex); + *sourceRow = sourceIndex.row(); + *sourceColumn = sourceIndex.column(); + *sourceParent = sourceIndex.parent(); + } +} + /*! \reimp \since 5.4 @@ -392,8 +412,11 @@ bool QAbstractProxyModel::canDropMimeData(const QMimeData *data, Qt::DropAction int row, int column, const QModelIndex &parent) const { Q_D(const QAbstractProxyModel); - const QModelIndex source = mapToSource(index(row, column, parent)); - return d->model->canDropMimeData(data, action, source.row(), source.column(), source.parent()); + int sourceDestinationRow; + int sourceDestinationColumn; + QModelIndex sourceParent; + d->mapDropCoordinatesToSource(row, column, parent, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent); + return d->model->canDropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent); } /*! @@ -404,8 +427,11 @@ bool QAbstractProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction act int row, int column, const QModelIndex &parent) { Q_D(QAbstractProxyModel); - const QModelIndex source = mapToSource(index(row, column, parent)); - return d->model->dropMimeData(data, action, source.row(), source.column(), source.parent()); + int sourceDestinationRow; + int sourceDestinationColumn; + QModelIndex sourceParent; + d->mapDropCoordinatesToSource(row, column, parent, &sourceDestinationRow, &sourceDestinationColumn, &sourceParent); + return d->model->dropMimeData(data, action, sourceDestinationRow, sourceDestinationColumn, sourceParent); } /*! diff --git a/src/corelib/itemmodels/qabstractproxymodel_p.h b/src/corelib/itemmodels/qabstractproxymodel_p.h index 9402092fa8..24af5afc64 100644 --- a/src/corelib/itemmodels/qabstractproxymodel_p.h +++ b/src/corelib/itemmodels/qabstractproxymodel_p.h @@ -59,6 +59,8 @@ public: QAbstractProxyModelPrivate() : QAbstractItemModelPrivate(), model(0) {} QAbstractItemModel *model; virtual void _q_sourceModelDestroyed(); + void mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent, + int *source_row, int *source_column, QModelIndex *source_parent) const; }; QT_END_NAMESPACE diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 3c383532bb..0b2b0e4188 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -2030,30 +2030,14 @@ Qt::DropActions QSortFilterProxyModel::supportedDropActions() const return d->model->supportedDropActions(); } +// Qt6: remove unnecessary reimplementation /*! \reimp */ bool QSortFilterProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { - Q_D(QSortFilterProxyModel); - if ((row == -1) && (column == -1)) - return d->model->dropMimeData(data, action, -1, -1, mapToSource(parent)); - int source_destination_row = -1; - int source_destination_column = -1; - QModelIndex source_parent; - if (row == rowCount(parent)) { - source_parent = mapToSource(parent); - source_destination_row = d->model->rowCount(source_parent); - } else { - QModelIndex proxy_index = index(row, column, parent); - QModelIndex source_index = mapToSource(proxy_index); - source_destination_row = source_index.row(); - source_destination_column = source_index.column(); - source_parent = source_index.parent(); - } - return d->model->dropMimeData(data, action, source_destination_row, - source_destination_column, source_parent); + return QAbstractProxyModel::dropMimeData(data, action, row, column, parent); } /*! diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 38a274947f..d05ed6c20f 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -144,6 +144,7 @@ private slots: void noMapAfterSourceDelete(); void forwardDropApi(); + void canDropMimeData(); protected: void buildHierarchy(const QStringList &data, QAbstractItemModel *model); @@ -3909,6 +3910,36 @@ void tst_QSortFilterProxyModel::chainedProxyModelRoleNames() QVERIFY(proxy2.roleNames().value(Qt::UserRole + 1) == "custom"); } +// A source model with ABABAB rows, where only A rows accept drops. +// It will then be sorted by a QSFPM. +class DropOnOddRows : public QAbstractListModel +{ + Q_OBJECT +public: + DropOnOddRows(QObject *parent = 0) : QAbstractListModel(parent) {} + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + if (role == Qt::DisplayRole) + return (index.row() % 2 == 0) ? "A" : "B"; + return QVariant(); + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + Q_UNUSED(parent); + return 10; + } + + bool canDropMimeData(const QMimeData *, Qt::DropAction, + int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE + { + Q_UNUSED(row); + Q_UNUSED(column); + return parent.row() % 2 == 0; + } +}; + class SourceAssertion : public QSortFilterProxyModel { Q_OBJECT @@ -3973,5 +4004,30 @@ void tst_QSortFilterProxyModel::forwardDropApi() QVERIFY(model.dropMimeData(0, Qt::CopyAction, 0, 0, QModelIndex())); } +static QString rowTexts(QAbstractItemModel *model) { + QString str; + for (int row = 0 ; row < model->rowCount(); ++row) + str += model->index(row, 0).data().toString(); + return str; +} + +void tst_QSortFilterProxyModel::canDropMimeData() +{ + // Given a source model which only supports dropping on even rows + DropOnOddRows sourceModel; + QCOMPARE(rowTexts(&sourceModel), QString("ABABABABAB")); + + // and a proxy model that sorts the rows + QSortFilterProxyModel proxy; + proxy.setSourceModel(&sourceModel); + proxy.sort(0, Qt::AscendingOrder); + QCOMPARE(rowTexts(&proxy), QString("AAAAABBBBB")); + + // the proxy should correctly map canDropMimeData to the source model, + // i.e. accept drops on the first 5 rows and refuse drops on the next 5. + for (int row = 0; row < proxy.rowCount(); ++row) + QCOMPARE(proxy.canDropMimeData(0, Qt::CopyAction, -1, -1, proxy.index(row, 0)), row < 5); +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" From b13aa15e1007a1b5ed61049bbd9ef8f95b6d12a5 Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 21 Nov 2014 10:46:22 +0100 Subject: [PATCH 322/323] QAbstractItemView: call canDropMimeData, as one would expect. The virtual method was added for 5.0 but never called. The old code (only checking mimetypes) is now the default implementation for canDropMimeData. Model subclasses can now refine this by having index-specific logic instead, or in order to inspect the dropped data (e.g. to accept files and refuse directories, which are all text/uri-list). [ChangeLog][QtWidgets][QAbstractItemView] now calls canDropMimeData in order to decide whether or not to accept the drop. Task-number: QTBUG-30534 Change-Id: Ied3aa964b4025bae6a1a26df89a681bfe61c3faa Reviewed-by: Stephen Kelly --- src/corelib/itemmodels/qabstractitemmodel.cpp | 17 +++++++++++---- .../doc/snippets/qlistview-dnd/main.cpp | 2 +- .../doc/snippets/qlistview-dnd/mainwindow.cpp | 2 +- .../doc/snippets/qlistview-dnd/model.cpp | 21 +++++++++++++++---- .../doc/snippets/qlistview-dnd/model.h | 2 ++ .../snippets/qlistview-dnd/qlistview-dnd.pro | 1 + .../doc/src/model-view-programming.qdoc | 3 +++ src/widgets/itemviews/qabstractitemview_p.h | 16 +++++++------- 8 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index b15d255e66..a9cfa3e7ca 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1842,7 +1842,9 @@ QMimeData *QAbstractItemModel::mimeData(const QModelIndexList &indexes) const /*! Returns \c{true} if a model can accept a drop of the \a data. This - default implementation always returns \c{true}. + default implementation only checks if \a data has at least one format + in the list of mimeTypes() and if \a action is among the + model's supportedDropActions(). Reimplement this function in your custom model, if you want to test whether the \a data can be dropped at \a row, \a column, @@ -1855,12 +1857,19 @@ bool QAbstractItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction a int row, int column, const QModelIndex &parent) const { - Q_UNUSED(data) - Q_UNUSED(action) Q_UNUSED(row) Q_UNUSED(column) Q_UNUSED(parent) - return true; + + if (!(action & supportedDropActions())) + return false; + + const QStringList modelTypes = mimeTypes(); + for (int i = 0; i < modelTypes.count(); ++i) { + if (data->hasFormat(modelTypes.at(i))) + return true; + } + return false; } /*! diff --git a/src/widgets/doc/snippets/qlistview-dnd/main.cpp b/src/widgets/doc/snippets/qlistview-dnd/main.cpp index c4a8aebb01..422ce35c6b 100644 --- a/src/widgets/doc/snippets/qlistview-dnd/main.cpp +++ b/src/widgets/doc/snippets/qlistview-dnd/main.cpp @@ -38,7 +38,7 @@ ** ****************************************************************************/ -#include +#include #include "mainwindow.h" diff --git a/src/widgets/doc/snippets/qlistview-dnd/mainwindow.cpp b/src/widgets/doc/snippets/qlistview-dnd/mainwindow.cpp index ed06819dd9..3b19295676 100644 --- a/src/widgets/doc/snippets/qlistview-dnd/mainwindow.cpp +++ b/src/widgets/doc/snippets/qlistview-dnd/mainwindow.cpp @@ -38,7 +38,7 @@ ** ****************************************************************************/ -#include +#include #include "mainwindow.h" #include "model.h" diff --git a/src/widgets/doc/snippets/qlistview-dnd/model.cpp b/src/widgets/doc/snippets/qlistview-dnd/model.cpp index 6ebeb2eb56..aa12cef3a2 100644 --- a/src/widgets/doc/snippets/qlistview-dnd/model.cpp +++ b/src/widgets/doc/snippets/qlistview-dnd/model.cpp @@ -65,18 +65,31 @@ DragDropListModel::DragDropListModel(const QStringList &strings, } //! [0] -bool DragDropListModel::dropMimeData(const QMimeData *data, +bool DragDropListModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { - if (action == Qt::IgnoreAction) - return true; + Q_UNUSED(action); + Q_UNUSED(row); + Q_UNUSED(parent); if (!data->hasFormat("application/vnd.text.list")) return false; if (column > 0) -//! [0] //! [1] return false; + + return true; +} +//! [0] +//! [1] +bool DragDropListModel::dropMimeData(const QMimeData *data, + Qt::DropAction action, int row, int column, const QModelIndex &parent) +{ + if (!canDropMimeData(data, action, row, column, parent)) + return false; + + if (action == Qt::IgnoreAction) + return true; //! [1] //! [2] diff --git a/src/widgets/doc/snippets/qlistview-dnd/model.h b/src/widgets/doc/snippets/qlistview-dnd/model.h index 9b667ad4a3..9217052971 100644 --- a/src/widgets/doc/snippets/qlistview-dnd/model.h +++ b/src/widgets/doc/snippets/qlistview-dnd/model.h @@ -63,6 +63,8 @@ public: Qt::ItemFlags flags(const QModelIndex &index) const; + bool canDropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent); bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); QMimeData *mimeData(const QModelIndexList &indexes) const; diff --git a/src/widgets/doc/snippets/qlistview-dnd/qlistview-dnd.pro b/src/widgets/doc/snippets/qlistview-dnd/qlistview-dnd.pro index 71fa273a69..bc2a1f0dce 100644 --- a/src/widgets/doc/snippets/qlistview-dnd/qlistview-dnd.pro +++ b/src/widgets/doc/snippets/qlistview-dnd/qlistview-dnd.pro @@ -3,3 +3,4 @@ SOURCES = main.cpp \ model.cpp HEADERS = mainwindow.h \ model.h +QT += widgets diff --git a/src/widgets/doc/src/model-view-programming.qdoc b/src/widgets/doc/src/model-view-programming.qdoc index 8978efa1e3..ada0460689 100644 --- a/src/widgets/doc/src/model-view-programming.qdoc +++ b/src/widgets/doc/src/model-view-programming.qdoc @@ -1769,6 +1769,9 @@ dropped onto existing items separately to data dropped into the top level of the model (i.e., onto an invalid item). + Models can forbid dropping on certain items, or depending on the dropped data, + by reimplementing QAbstractItemModel::canDropMimeData(). + The model first has to make sure that the operation should be acted on, the data supplied is in a format that can be used, and that its destination within the model is valid: diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index 047533b22c..e04f08da36 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -164,13 +164,15 @@ public: #ifndef QT_NO_DRAGANDDROP virtual QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const; - inline bool canDecode(QDropEvent *e) const { - QStringList modelTypes = model->mimeTypes(); - const QMimeData *mime = e->mimeData(); - for (int i = 0; i < modelTypes.count(); ++i) - if (mime->hasFormat(modelTypes.at(i)) - && (e->dropAction() & model->supportedDropActions())) - return true; + inline bool canDecode(QDropEvent *event) { + QModelIndex index; + int col = -1; + int row = -1; + if (dropOn(event, &row, &col, &index)) { + return model->canDropMimeData(event->mimeData(), + dragDropMode == QAbstractItemView::InternalMove ? Qt::MoveAction : event->dropAction(), + row, col, index); + } return false; } From b1cf07f495e10c93e53651ac03e46ebdaea0a97e Mon Sep 17 00:00:00 2001 From: David Faure Date: Fri, 21 Nov 2014 00:43:54 +0100 Subject: [PATCH 323/323] QAbstractItemView: rename private canDecode to canDrop. Change-Id: I9b1b3ead0bea35a75e20c5c18e288251de7ad7fe Reviewed-by: Stephen Kelly --- src/widgets/itemviews/qabstractitemview.cpp | 6 +++--- src/widgets/itemviews/qabstractitemview_p.h | 2 +- src/widgets/itemviews/qlistview.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 1d8be6398c..16de80476f 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -1904,7 +1904,7 @@ void QAbstractItemView::dragEnterEvent(QDragEnterEvent *event) && (event->source() != this|| !(event->possibleActions() & Qt::MoveAction))) return; - if (d_func()->canDecode(event)) { + if (d_func()->canDrop(event)) { event->accept(); setState(DraggingState); } else { @@ -1933,7 +1933,7 @@ void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event) QModelIndex index = indexAt(event->pos()); d->hover = index; if (!d->droppingOnItself(event, index) - && d->canDecode(event)) { + && d->canDrop(event)) { if (index.isValid() && d->showDropIndicator) { QRect rect = visualRect(index); @@ -1978,7 +1978,7 @@ void QAbstractItemView::dragMoveEvent(QDragMoveEvent *event) } } d->viewport->update(); - } // can decode + } // can drop if (d->shouldAutoScroll(event->pos())) startAutoScroll(); diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index e04f08da36..c3bd1fb504 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -164,7 +164,7 @@ public: #ifndef QT_NO_DRAGANDDROP virtual QAbstractItemView::DropIndicatorPosition position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const; - inline bool canDecode(QDropEvent *event) { + inline bool canDrop(QDropEvent *event) { QModelIndex index; int col = -1; int row = -1; diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index a097228846..e7d18092f1 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1977,7 +1977,7 @@ void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event) ? intersectVector.last() : QModelIndex(); dd->hover = index; if (!dd->droppingOnItself(event, index) - && dd->canDecode(event)) { + && dd->canDrop(event)) { if (index.isValid() && dd->showDropIndicator) { QRect rect = qq->visualRect(index); @@ -2023,7 +2023,7 @@ void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event) } } dd->viewport->update(); - } // can decode + } // can drop if (dd->shouldAutoScroll(event->pos())) qq->startAutoScroll(); @@ -2757,7 +2757,7 @@ bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e) bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e) { - if (e->source() != qq || !dd->canDecode(e)) + if (e->source() != qq || !dd->canDrop(e)) return false; // ignore by default