diff options
Diffstat (limited to 'src/gui')
68 files changed, 927 insertions, 603 deletions
diff --git a/src/gui/configure.json b/src/gui/configure.json index 19312d245d..7f4d7cc6af 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -41,11 +41,10 @@ "sm": { "type": "boolean", "name": "sessionmanager" }, "tslib": "boolean", "vulkan": "boolean", - "xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] }, + "xcb": "boolean", + "bundled-xcb-xinput": "boolean", "xcb-native-painting": "boolean", "xcb-xlib": "boolean", - "xcb-xinput": "boolean", - "xkb": "boolean", "xkbcommon": "boolean" } }, @@ -573,18 +572,22 @@ ] }, "xcb": { - "label": "XCB >= 1.9", + "label": "XCB >= 1.11", "test": { "main": [ "int primaryScreen = 0;", "(void)xcb_connect(\"\", &primaryScreen);", - "// This won't compile unless libxcb >= 1.9 which defines XCB_CONN_CLOSED_INVALID_SCREEN.", - "int xcbScreenError = XCB_CONN_CLOSED_INVALID_SCREEN;" + "/* XCB_PACKED define was added in libxcb 1.11 */", + "#ifdef XCB_PACKED", + " return 0;", + "#else", + " return -1;", + "#endif" ] }, "headers": "xcb/xcb.h", "sources": [ - { "type": "pkgConfig", "args": "xcb >= 1.9" }, + { "type": "pkgConfig", "args": "xcb >= 1.11" }, "-lxcb" ] }, @@ -691,21 +694,10 @@ "use": "xcb xlib" }, "xcb_xkb": { - "label": "XCB XKB >= 1.10", - "test": { - "head": [ - "// xkb.h is using a variable called 'explicit', which is a reserved keyword in C++", - "#define explicit dont_use_cxx_explicit" - ], - "tail": "#undef explicit", - "main": [ - "// This takes more arguments in xcb-xkb < 1.10.", - "xcb_xkb_get_kbd_by_name_unchecked(NULL, 0, 0, 0, 0);" - ] - }, + "label": "XCB XKB", "headers": "xcb/xkb.h", "sources": [ - { "type": "pkgConfig", "args": "xcb-xkb >= 1.10" }, + { "type": "pkgConfig", "args": "xcb-xkb" }, "-lxcb-xkb" ], "use": "xcb" @@ -769,7 +761,7 @@ "xkbcommon_x11": { "label": "xkbcommon-x11", "test": { - "main": "xkb_x11_get_core_keyboard_device_id(nullptr);" + "main": "xkb_x11_setup_xkb_extension_flags flag = XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS;" }, "headers": [ "xkbcommon/xkbcommon-x11.h" ], "sources": [ @@ -1056,6 +1048,11 @@ "label": "XCB (extensions)", "type": "compile", "test": { + "head": [ + "// xkb.h is using a variable called 'explicit', which is a reserved keyword in C++", + "#define explicit dont_use_cxx_explicit" + ], + "tail": "#undef explicit", "include": [ "xcb/xcb.h", "xcb/xcb_image.h", @@ -1068,7 +1065,8 @@ "xcb/xfixes.h", "xcb/xinerama.h", "xcb/xcb_icccm.h", - "xcb/xcb_renderutil.h" + "xcb/xcb_renderutil.h", + "xcb/xkb.h" ], "main": [ "int primaryScreen = 0;", @@ -1082,10 +1080,13 @@ " xcb_render_query_pict_formats_reply(c, formatsCookie, &error);", "/* RENDERUTIL: xcb_renderutil.h include won't compile unless version >= 0.3.9 */", - "xcb_render_util_find_standard_format(nullptr, XCB_PICT_STANDARD_ARGB_32);" + "xcb_render_util_find_standard_format(nullptr, XCB_PICT_STANDARD_ARGB_32);", + + "/* XKB: This takes more arguments in xcb-xkb < 1.11 */", + "xcb_xkb_get_kbd_by_name_replies_key_names_value_list_sizeof(nullptr, 0, 0, 0, 0, 0, 0, 0, 0);" ] }, - "use": "xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb" + "use": "xcb_icccm xcb_image xcb_keysyms xcb_randr xcb_render xcb_renderutil xcb_shape xcb_shm xcb_sync xcb_xfixes xcb_xinerama xcb_xkb xcb" }, "x11prefix": { "label": "X11 prefix", @@ -1314,7 +1315,7 @@ }, "opengles3": { "label": "OpenGL ES 3.0", - "condition": "features.opengles2 && !features.angle && tests.opengles3 && !config.wasm", + "condition": "features.opengles2 && !features.angle && tests.opengles3", "output": [ "publicFeature", { "type": "define", "name": "QT_OPENGL_ES_3" } @@ -1514,16 +1515,7 @@ "label": "XCB", "section": "Platform plugins", "autoDetect": "!config.darwin", - "enable": "input.xcb == 'system' || input.xcb == 'qt' || input.xcb == 'yes'", - "condition": "features.thread && features.xkbcommon && libs.xcb", - "output": [ "privateFeature" ] - }, - "system-xcb": { - "label": "Using system-provided XCB libraries", - "enable": "input.xcb == 'system'", - "disable": "input.xcb == 'qt'", - "autoDetect": "!config.darwin", - "condition": "features.xcb && tests.xcb_syslibs", + "condition": "features.thread && libs.xcb && tests.xcb_syslibs && features.xkbcommon-x11", "output": [ "privateFeature" ] }, "x11-prefix": { @@ -1562,12 +1554,6 @@ "condition": "features.xcb-native-painting", "output": [ "privateFeature" ] }, - "xkb": { - "label": "XCB XKB", - "emitIf": "features.xcb", - "condition": "(!features.system-xcb || libs.xcb_xkb) && libs.xkbcommon_x11", - "output": [ "privateFeature" ] - }, "xcb-xlib": { "label": "XCB Xlib", "condition": "features.xlib && libs.xcb_xlib", @@ -1579,10 +1565,12 @@ "condition": "features.sessionmanager && libs.x11sm", "output": [ "privateFeature" ] }, - "xcb-xinput": { - "label": "XCB XInput", + "system-xcb-xinput": { + "label": "Using system-provided xcb-xinput", "emitIf": "features.xcb", - "condition": "!features.system-xcb || libs.xcb_xinput", + "disable": "input.bundled-xcb-xinput == 'yes'", + "enable": "input.bundled-xcb-xinput == 'no'", + "condition": "libs.xcb_xinput", "output": [ "privateFeature" ] }, "xkbcommon": { @@ -1590,6 +1578,11 @@ "condition": "libs.xkbcommon", "output": [ "privateFeature" ] }, + "xkbcommon-x11": { + "label": "xkbcommon-x11", + "condition": "features.xkbcommon && libs.xkbcommon_x11", + "output": [ "privateFeature" ] + }, "xlib": { "label": "XLib", "autoDetect": "!config.darwin || features.xcb", @@ -1831,7 +1824,7 @@ { "type": "error", "condition": "input.xcb != '' && input.xcb != 'no' && input.xkbcommon == 'no'", - "message": "XCB plugin requires xkbcommon, but -no-xkbcommon was provided." + "message": "XCB plugin requires xkbcommon and xkbcommon-x11, but -no-xkbcommon was provided." } ], @@ -1953,7 +1946,8 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla "entries": [ "xlib", "xcb-xlib", - "egl_x11" + "egl_x11", + "xkbcommon-x11" ] } ] @@ -1986,7 +1980,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla "section": "XCB", "condition": "features.xcb", "entries": [ - "system-xcb", "xkb", "xcb-xinput", "xcb-native-painting", + "system-xcb-xinput", "xcb-native-painting", { "section": "GL integrations", "entries": [ diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 45c8c05162..350d4c5ee3 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -99,4 +99,4 @@ qtConfig(egl): CMAKE_EGL_INCDIRS = $$cmakePortablePaths($$QMAKE_INCDIR_EGL) QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist TRACEPOINT_PROVIDER = $$PWD/qtgui.tracepoints -CONFIG += qt_tracepoints +CONFIG += qt_tracepoints metatypes install_metatypes diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index d8ed0829af..869e206524 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1912,10 +1912,10 @@ void QImage::invertPixels(InvertMode mode) // Inverting premultiplied pixels would produce invalid image data. if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) { if (depth() > 32) { - if (!d->convertInPlace(QImage::Format_RGBA64, 0)) + if (!d->convertInPlace(QImage::Format_RGBA64, { })) *this = convertToFormat(QImage::Format_RGBA64); } else { - if (!d->convertInPlace(QImage::Format_ARGB32, 0)) + if (!d->convertInPlace(QImage::Format_ARGB32, { })) *this = convertToFormat(QImage::Format_ARGB32); } } @@ -1982,7 +1982,7 @@ void QImage::invertPixels(InvertMode mode) } if (originalFormat != d->format) { - if (!d->convertInPlace(originalFormat, 0)) + if (!d->convertInPlace(originalFormat, { })) *this = convertToFormat(originalFormat); } } diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 97a5f89e68..8f33a13b95 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -257,7 +257,8 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im // Cannot be used with indexed formats or between formats with different pixel depths. Q_ASSERT(dst_format > QImage::Format_Indexed8); Q_ASSERT(data->format > QImage::Format_Indexed8); - if (data->depth != qt_depthForFormat(dst_format)) + const int destDepth = qt_depthForFormat(dst_format); + if (data->depth < destDepth) return false; const QPixelLayout *srcLayout = &qPixelLayouts[data->format]; @@ -272,9 +273,16 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im uint buf[BufferSize]; uint *buffer = buf; uchar *srcData = data->data; + uchar *destData = data->data; - Q_ASSERT(srcLayout->bpp == destLayout->bpp); - Q_ASSERT(srcLayout->bpp != QPixelLayout::BPP64); + QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes }; + if (data->depth != destDepth) { + params = QImageData::calculateImageParameters(data->width, data->height, destDepth); + if (!params.isValid()) + return false; + } + + Q_ASSERT(destLayout->bpp != QPixelLayout::BPP64); FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM; ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM; if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) { @@ -316,15 +324,26 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im while (x < data->width) { dither.x = x; int l = data->width - x; - if (destLayout->bpp == QPixelLayout::BPP32) + if (srcLayout->bpp == QPixelLayout::BPP32) buffer = reinterpret_cast<uint *>(srcData) + x; else l = qMin(l, BufferSize); const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr); - store(srcData, ptr, x, l, nullptr, ditherPtr); + store(destData, ptr, x, l, nullptr, ditherPtr); x += l; } srcData += data->bytes_per_line; + destData += params.bytesPerLine; + } + if (params.totalSize != data->nbytes) { + Q_ASSERT(params.totalSize < data->nbytes); + void *newData = realloc(data->data, params.totalSize); + if (newData) { + data->data = (uchar *)newData; + data->nbytes = params.totalSize; + } + data->bytes_per_line = params.bytesPerLine; + data->depth = destDepth; } data->format = dst_format; return true; @@ -832,240 +851,6 @@ static bool convert_A2RGB30_PM_to_ARGB_inplace(QImageData *data, Qt::ImageConver return true; } -static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - Q_ASSERT(data->own_data); - - const int depth = 32; - auto params = QImageData::calculateImageParameters(data->width, data->height, depth); - if (params.bytesPerLine < 0) - return false; - uchar *const newData = (uchar *)realloc(data->data, params.totalSize); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; // end of src - quint32 *dest_data = (quint32 *) (newData + params.totalSize); // end of dest > end of src - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (params.bytesPerLine >> 2) - width; - if (data->colortable.size() == 0) { - data->colortable.resize(256); - for (int i = 0; i < 256; ++i) - data->colortable[i] = qRgb(i, i, i); - } else { - for (int i = 0; i < data->colortable.size(); ++i) - data->colortable[i] = qPremultiply(data->colortable.at(i)); - - // Fill the rest of the table in case src_data > colortable.size() - const int oldSize = data->colortable.size(); - const QRgb lastColor = data->colortable.at(oldSize - 1); - data->colortable.insert(oldSize, 256 - oldSize, lastColor); - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = data->colortable.at(*src_data); - } - } - - data->colortable = QVector<QRgb>(); - data->format = QImage::Format_ARGB32_Premultiplied; - data->bytes_per_line = params.bytesPerLine; - data->depth = depth; - data->nbytes = params.totalSize; - - return true; -} - -static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - Q_ASSERT(data->own_data); - - const int depth = 32; - auto params = QImageData::calculateImageParameters(data->width, data->height, depth); - if (params.bytesPerLine < 0) - return false; - uchar *const newData = (uchar *)realloc(data->data, params.totalSize); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; - quint32 *dest_data = (quint32 *) (newData + params.totalSize); - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (params.bytesPerLine >> 2) - width; - if (data->colortable.size() == 0) { - data->colortable.resize(256); - for (int i = 0; i < 256; ++i) - data->colortable[i] = qRgb(i, i, i); - } else { - // Fill the rest of the table in case src_data > colortable.size() - const int oldSize = data->colortable.size(); - const QRgb lastColor = data->colortable.at(oldSize - 1); - data->colortable.insert(oldSize, 256 - oldSize, lastColor); - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = (quint32) data->colortable.at(*src_data); - } - } - - data->colortable = QVector<QRgb>(); - data->format = QImage::Format_ARGB32; - data->bytes_per_line = params.bytesPerLine; - data->depth = depth; - data->nbytes = params.totalSize; - - return true; -} - -static bool convert_indexed8_to_RGB_inplace(QImageData *data, Qt::ImageConversionFlags flags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - Q_ASSERT(data->own_data); - - if (data->has_alpha_clut) { - for (int i = 0; i < data->colortable.size(); ++i) - data->colortable[i] |= 0xff000000; - } - - if (!convert_indexed8_to_ARGB_inplace(data, flags)) - return false; - - data->format = QImage::Format_RGB32; - return true; -} - -static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_Indexed8); - Q_ASSERT(data->own_data); - - const int depth = 16; - auto params = QImageData::calculateImageParameters(data->width, data->height, depth); - if (params.bytesPerLine < 0) - return false; - uchar *const newData = (uchar *)realloc(data->data, params.totalSize); - if (!newData) - return false; - - data->data = newData; - - // start converting from the end because the end image is bigger than the source - uchar *src_data = newData + data->nbytes; - quint16 *dest_data = (quint16 *) (newData + params.totalSize); - const int width = data->width; - const int src_pad = data->bytes_per_line - width; - const int dest_pad = (params.bytesPerLine >> 1) - width; - - quint16 colorTableRGB16[256]; - const int tableSize = data->colortable.size(); - if (tableSize == 0) { - for (int i = 0; i < 256; ++i) - colorTableRGB16[i] = qConvertRgb32To16(qRgb(i, i, i)); - } else { - // 1) convert the existing colors to RGB16 - for (int i = 0; i < tableSize; ++i) - colorTableRGB16[i] = qConvertRgb32To16(data->colortable.at(i)); - data->colortable = QVector<QRgb>(); - - // 2) fill the rest of the table in case src_data > colortable.size() - const quint16 lastColor = colorTableRGB16[tableSize - 1]; - for (int i = tableSize; i < 256; ++i) - colorTableRGB16[i] = lastColor; - } - - for (int i = 0; i < data->height; ++i) { - src_data -= src_pad; - dest_data -= dest_pad; - for (int pixI = 0; pixI < width; ++pixI) { - --src_data; - --dest_data; - *dest_data = colorTableRGB16[*src_data]; - } - } - - data->format = QImage::Format_RGB16; - data->bytes_per_line = params.bytesPerLine; - data->depth = depth; - data->nbytes = params.totalSize; - - return true; -} - -static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFlags) -{ - Q_ASSERT(data->format == QImage::Format_RGB32); - Q_ASSERT(data->own_data); - - const int depth = 16; - - // cannot overflow, since we're shrinking the buffer - const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2; - const qsizetype src_bytes_per_line = data->bytes_per_line; - quint32 *src_data = (quint32 *) data->data; - quint16 *dst_data = (quint16 *) data->data; - - for (int i = 0; i < data->height; ++i) { - for (int j = 0; j < data->width; ++j) - dst_data[j] = qConvertRgb32To16(src_data[j]); - src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line); - dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line); - } - data->format = QImage::Format_RGB16; - data->bytes_per_line = dst_bytes_per_line; - data->depth = depth; - data->nbytes = dst_bytes_per_line * data->height; - uchar *const newData = (uchar *)realloc(data->data, data->nbytes); - if (newData) - data->data = newData; - - // can't fail, since we're shrinking - return true; -} - -static void convert_ARGB_PM_to_ARGB(QImageData *dest, const QImageData *src) -{ - Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied || src->format == QImage::Format_RGBA8888_Premultiplied); - Q_ASSERT(dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_RGBA8888); - Q_ASSERT(src->width == dest->width); - Q_ASSERT(src->height == dest->height); - - const int src_pad = (src->bytes_per_line >> 2) - src->width; - const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; - const QRgb *src_data = (QRgb *) src->data; - QRgb *dest_data = (QRgb *) dest->data; - - for (int i = 0; i < src->height; ++i) { - const QRgb *end = src_data + src->width; - while (src_data < end) { - *dest_data = qUnpremultiply(*src_data); - ++src_data; - ++dest_data; - } - src_data += src_pad; - dest_data += dest_pad; - } -} - static void convert_RGBA_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_RGBA8888 || src->format == QImage::Format_RGBX8888); @@ -1732,7 +1517,7 @@ static void convert_X_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageC static void convert_ARGB_PM_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) { QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src); + convert_generic(tmp.data(), src, Qt::AutoColor); dither_to_Mono(dst, tmp.data(), flags, false); } @@ -2012,7 +1797,7 @@ static void convert_RGB_to_Indexed8(QImageData *dst, const QImageData *src, Qt:: static void convert_ARGB_PM_to_Indexed8(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags) { QScopedPointer<QImageData> tmp(QImageData::create(QSize(src->width, src->height), QImage::Format_ARGB32)); - convert_ARGB_PM_to_ARGB(tmp.data(), src); + convert_generic(tmp.data(), src, Qt::AutoColor); convert_RGB_to_Indexed8(dst, tmp.data(), flags); } @@ -2991,10 +2776,10 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - convert_indexed8_to_RGB_inplace, - convert_indexed8_to_ARGB_inplace, - convert_indexed8_to_ARGB_PM_inplace, - convert_indexed8_to_RGB16_inplace, + 0, + 0, + 0, + 0, 0, 0, 0, @@ -3018,7 +2803,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, mask_alpha_converter_inplace<QImage::Format_ARGB32>, mask_alpha_converter_inplace<QImage::Format_ARGB32_Premultiplied>, - convert_RGB_to_RGB16_inplace, + 0, 0, 0, 0, diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 4ab45337b0..d6caf6773a 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -174,7 +174,7 @@ public: void setGamma(float); bool writeImage(const QImage& img, int x, int y); - bool writeImage(const QImage& img, volatile int compression_in, const QString &description, int x, int y); + bool writeImage(const QImage& img, int compression_in, const QString &description, int x, int y); bool writeImage(const QImage& img) { return writeImage(img, 0, 0); } bool writeImage(const QImage& img, int compression, const QString &description) @@ -900,7 +900,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, int off_x, int off_y) return writeImage(image, -1, QString(), off_x, off_y); } -bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_in, const QString &description, +bool QPNGImageWriter::writeImage(const QImage& image, int compression_in, const QString &description, int off_x_in, int off_y_in) { QPoint offset = image.offset(); diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 54f3996b6e..ef31e475ea 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1040,7 +1040,9 @@ QList<QScreen *> QGuiApplication::screens() The \a point is in relation to the virtualGeometry() of each set of virtual siblings. If the point maps to more than one set of virtual siblings the first - match is returned. + match is returned. If you wish to search only the virtual desktop siblings + of a known screen (for example siblings of the screen of your application + window \c QWidget::windowHandle()->screen()), use QScreen::virtualSiblingAt(). \since 5.10 */ @@ -1694,13 +1696,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() qt_gl_set_global_share_context(0); } #endif -#ifdef Q_OS_WASM - EM_ASM( - // unmount persistent directory as IDBFS - // see QTBUG-70002 - FS.unmount('/home/web_user'); - ); -#endif + platform_integration->destroy(); delete platform_theme; @@ -1767,7 +1763,7 @@ Qt::KeyboardModifiers QGuiApplication::keyboardModifiers() */ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers() { - CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers(0)) + CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{}) QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); return pi->queryKeyboardModifiers(); } diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 26f65b2f16..ee493faa5d 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -116,7 +116,7 @@ public: static QAbstractEventDispatcher *qt_qpa_core_dispatcher() { if (QCoreApplication::instance()) - return QCoreApplication::instance()->d_func()->threadData->eventDispatcher.loadRelaxed(); + return QCoreApplication::instance()->d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed(); else return nullptr; } diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index f58944a7d2..3c85481495 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -313,7 +313,7 @@ public: static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; } static inline QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; } static inline QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window) { return pos; } - static inline QDpi logicalDpi() { return QDpi(-1,-1); } + static inline QDpi logicalDpi(const QScreen *screen) { return QDpi(-1,-1); } }; namespace QHighDpi { diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp index 49eff2ad23..34c4549443 100644 --- a/src/gui/kernel/qplatformcursor.cpp +++ b/src/gui/kernel/qplatformcursor.cpp @@ -103,7 +103,7 @@ QT_BEGIN_NAMESPACE QPlatformCursor::clearOverrideCursor(). */ -QPlatformCursor::Capabilities QPlatformCursor::m_capabilities = 0; +QPlatformCursor::Capabilities QPlatformCursor::m_capabilities = { }; /*! \fn QPlatformCursor::QPlatformCursor() diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 4bee153489..15ac4acf91 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -186,7 +186,7 @@ QVariant QPlatformDialogHelper::defaultStyleHint(QPlatformDialogHelper::StyleHi class QFontDialogOptionsPrivate : public QSharedData { public: - QFontDialogOptionsPrivate() : options(0) {} + QFontDialogOptionsPrivate() = default; QFontDialogOptions::FontDialogOptions options; QString windowTitle; @@ -328,7 +328,7 @@ Q_GLOBAL_STATIC(QColorDialogStaticData, qColorDialogStaticData) class QColorDialogOptionsPrivate : public QSharedData { public: - QColorDialogOptionsPrivate() : options(0) {} + QColorDialogOptionsPrivate() = default; // Write out settings around destruction of dialogs ~QColorDialogOptionsPrivate() { qColorDialogStaticData()->writeSettings(); } @@ -465,24 +465,16 @@ void QPlatformColorDialogHelper::setOptions(const QSharedPointer<QColorDialogOpt class QFileDialogOptionsPrivate : public QSharedData { public: - QFileDialogOptionsPrivate() : options(0), - viewMode(QFileDialogOptions::Detail), - fileMode(QFileDialogOptions::AnyFile), - acceptMode(QFileDialogOptions::AcceptOpen), - filters(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs), - useDefaultNameFilters(true) - {} - QFileDialogOptions::FileDialogOptions options; QString windowTitle; - QFileDialogOptions::ViewMode viewMode; - QFileDialogOptions::FileMode fileMode; - QFileDialogOptions::AcceptMode acceptMode; + QFileDialogOptions::ViewMode viewMode = QFileDialogOptions::Detail; + QFileDialogOptions::FileMode fileMode = QFileDialogOptions::AnyFile; + QFileDialogOptions::AcceptMode acceptMode = QFileDialogOptions::AcceptOpen; QString labels[QFileDialogOptions::DialogLabelCount]; - QDir::Filters filters; + QDir::Filters filters = QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs; QList<QUrl> sidebarUrls; - bool useDefaultNameFilters; + bool useDefaultNameFilters = true; QStringList nameFilters; QStringList mimeTypeFilters; QString defaultSuffix; diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index d9f349555a..01406958e2 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -106,7 +106,8 @@ public: ApplicationIcon, SwitchableWidgetComposition, TopStackedNativeChildWindows, - OpenGLOnRasterSurface + OpenGLOnRasterSurface, + MaximizeUsingFullscreenGeometry }; virtual ~QPlatformIntegration() { } diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index f3213bf5ea..e511a6f5c4 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -410,15 +410,22 @@ void QPlatformScreen::resizeMaximizedWindows() const QRect newGeometry = deviceIndependentGeometry(); const QRect newAvailableGeometry = QHighDpi::fromNative(availableGeometry(), QHighDpiScaling::factor(this), newGeometry.topLeft()); + const bool supportsMaximizeUsingFullscreen = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MaximizeUsingFullscreenGeometry); + for (QWindow *w : windows()) { // Skip non-platform windows, e.g., offscreen windows. if (!w->handle()) continue; - if (w->windowState() & Qt::WindowMaximized || w->geometry() == oldAvailableGeometry) + if (supportsMaximizeUsingFullscreen + && w->windowState() & Qt::WindowMaximized + && w->flags() & Qt::MaximizeUsingFullscreenGeometryHint) { + w->setGeometry(newGeometry); + } else if (w->windowState() & Qt::WindowMaximized || w->geometry() == oldAvailableGeometry) { w->setGeometry(newAvailableGeometry); - else if (w->windowState() & Qt::WindowFullScreen || w->geometry() == oldGeometry) + } else if (w->windowState() & Qt::WindowFullScreen || w->geometry() == oldGeometry) { w->setGeometry(newGeometry); + } } } @@ -609,4 +616,18 @@ int QPlatformScreen::preferredMode() const return 0; } +QList<QPlatformScreen *> QPlatformPlaceholderScreen::virtualSiblings() const +{ + QList<QPlatformScreen *> siblings; + + if (!m_virtualSibling) + return siblings; + + for (QScreen *screen : QGuiApplication::screens()) { + if (screen->handle() && screen->handle() != this) + siblings << screen->handle(); + } + return siblings; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index d7378aed51..0be7646032 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -105,6 +105,8 @@ public: QPlatformScreen(); virtual ~QPlatformScreen(); + virtual bool isPlaceholder() const { return false; } + virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const; virtual QRect geometry() const = 0; @@ -172,6 +174,27 @@ private: friend class QScreenPrivate; }; +// Qt doesn't currently support running with no platform screen +// QPA plugins can use this class to create a fake screen +class Q_GUI_EXPORT QPlatformPlaceholderScreen : public QPlatformScreen { +public: + // virtualSibling can be passed in to make the placeholder a sibling with other screens during + // the transitioning phase when the real screen is about to be removed, or the first real screen + // is about to be added. This is useful because Qt will currently recreate (but now show!) + // windows when they are moved from one virtual desktop to another, so if the last monitor is + // unplugged, then plugged in again, windows will be hidden unless the placeholder belongs to + // the same virtual desktop as the other screens. + QPlatformPlaceholderScreen(bool virtualSibling = true) : m_virtualSibling(virtualSibling) {} + bool isPlaceholder() const override { return true; } + QRect geometry() const override { return QRect(); } + QRect availableGeometry() const override { return QRect(); } + int depth() const override { return 32; } + QImage::Format format() const override { return QImage::Format::Format_RGB32; } + QList<QPlatformScreen *> virtualSiblings() const override; +private: + bool m_virtualSibling = true; +}; + QT_END_NAMESPACE #endif // QPLATFORMSCREEN_H diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 356c4ea3ea..3185fc4541 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -309,7 +309,7 @@ public: virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const; virtual QIcon fileIcon(const QFileInfo &fileInfo, - QPlatformTheme::IconOptions iconOptions = nullptr) const; + QPlatformTheme::IconOptions iconOptions = { }) const; virtual QIconEngine *createIconEngine(const QString &iconName) const; #ifndef QT_NO_SHORTCUT diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 7adf3db1b8..80de561297 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -700,6 +700,25 @@ void QScreenPrivate::updatePrimaryOrientation() } /*! + Returns the screen at \a point within the set of \l QScreen::virtualSiblings(), + or \c nullptr if outside of any screen. + + The \a point is in relation to the virtualGeometry() of each set of virtual + siblings. + + \since 5.15 +*/ +QScreen *QScreen::virtualSiblingAt(const QPoint &point) +{ + const auto &siblings = virtualSiblings(); + for (QScreen *sibling : siblings) { + if (sibling->geometry().contains(point)) + return sibling; + } + return nullptr; +} + +/*! Creates and returns a pixmap constructed by grabbing the contents of the given \a window restricted by QRect(\a x, \a y, \a width, \a height). diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index 14392d3036..88925ab731 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -125,6 +125,7 @@ public: QRect availableGeometry() const; QList<QScreen *> virtualSiblings() const; + QScreen *virtualSiblingAt(const QPoint &point); QSize virtualSize() const; QRect virtualGeometry() const; diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 0395c1db38..9ed450b031 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -45,6 +45,7 @@ #include "qvector.h" #include "qcoreapplication.h" #include <private/qkeymapper_p.h> +#include <QtCore/qloggingcategory.h> #include <algorithm> @@ -52,8 +53,7 @@ QT_BEGIN_NAMESPACE -// To enable verbose output uncomment below -//#define DEBUG_QSHORTCUTMAP +Q_LOGGING_CATEGORY(lcShortcutMap, "qt.gui.shortcutmap") /* \internal Entry data for QShortcutMap @@ -165,11 +165,9 @@ int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::Short QShortcutEntry newEntry(owner, key, context, --(d->currentId), true, matcher); const auto it = std::upper_bound(d->sequences.begin(), d->sequences.end(), newEntry); d->sequences.insert(it, newEntry); // Insert sorted -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() + qCDebug(lcShortcutMap).nospace() << "QShortcutMap::addShortcut(" << owner << ", " << key << ", " << context << ") = " << d->currentId; -#endif return d->currentId; } @@ -212,11 +210,9 @@ int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key return itemsRemoved; --i; } -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() + qCDebug(lcShortcutMap).nospace() << "QShortcutMap::removeShortcut(" << id << ", " << owner << ", " << key << ") = " << itemsRemoved; -#endif return itemsRemoved; } @@ -250,11 +246,9 @@ int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const return itemsChanged; --i; } -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() + qCDebug(lcShortcutMap).nospace() << "QShortcutMap::setShortcutEnabled(" << enable << ", " << id << ", " << owner << ", " << key << ") = " << itemsChanged; -#endif return itemsChanged; } @@ -288,11 +282,9 @@ int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const Q return itemsChanged; --i; } -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() + qCDebug(lcShortcutMap).nospace() << "QShortcutMap::setShortcutAutoRepeat(" << on << ", " << id << ", " << owner << ", " << key << ") = " << itemsChanged; -#endif return itemsChanged; } @@ -395,9 +387,7 @@ QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e) clearSequence(d->currentSequences); d->currentState = result; -#if defined(DEBUG_QSHORTCUTMAP) - qDebug().nospace() << "QShortcutMap::nextState(" << e << ") = " << result; -#endif + qCDebug(lcShortcutMap).nospace() << "QShortcutMap::nextState(" << e << ") = " << result; return result; } @@ -436,9 +426,7 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier return QKeySequence::NoMatch; createNewSequences(e, d->newEntries, ignoredModifiers); -#if defined(DEBUG_QSHORTCUTMAP) - qDebug() << "Possible shortcut key sequences:" << d->newEntries; -#endif + qCDebug(lcShortcutMap) << "Possible shortcut key sequences:" << d->newEntries; // Should never happen if (d->newEntries == d->currentSequences) { @@ -491,15 +479,11 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier // previous list. If this match is equal or better than the last match, append to the list if (oneKSResult > result) { okEntries.clear(); -#if defined(DEBUG_QSHORTCUTMAP) - qDebug() << "Found better match (" << d->newEntries << "), clearing key sequence list"; -#endif + qCDebug(lcShortcutMap) << "Found better match (" << d->newEntries << "), clearing key sequence list"; } if (oneKSResult && oneKSResult >= result) { okEntries << d->newEntries.at(i); -#if defined(DEBUG_QSHORTCUTMAP) - qDebug() << "Added ok key sequence" << d->newEntries; -#endif + qCDebug(lcShortcutMap) << "Added ok key sequence" << d->newEntries; } } @@ -515,9 +499,7 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier } if (result != QKeySequence::NoMatch) d->currentSequences = okEntries; -#if defined(DEBUG_QSHORTCUTMAP) - qDebug() << "Returning shortcut match == " << result; -#endif + qCDebug(lcShortcutMap) << "Returning shortcut match == " << result; return QKeySequence::SequenceMatch(result); } @@ -540,19 +522,16 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl, { Q_D(QShortcutMap); QList<int> possibleKeys = QKeyMapper::possibleKeys(e); -#if defined(DEBUG_QSHORTCUTMAP) - { - QDebug debug = qDebug().nospace(); - debug << __FUNCTION__ << '(' << e << ", ignoredModifiers=" + if (lcShortcutMap().isDebugEnabled()) { + qCDebug(lcShortcutMap).nospace() << __FUNCTION__ << '(' << e << ", ignoredModifiers=" << Qt::KeyboardModifiers(ignoredModifiers) << "), possibleKeys=("; for (int i = 0, size = possibleKeys.size(); i < size; ++i) { if (i) - debug << ", "; - debug << QKeySequence(possibleKeys.at(i)); + qCDebug(lcShortcutMap).nospace() << ", "; + qCDebug(lcShortcutMap).nospace() << QKeySequence(possibleKeys.at(i)); } - debug << ')'; + qCDebug(lcShortcutMap).nospace() << ')'; } -#endif // DEBUG_QSHORTCUTMAP int pkTotal = possibleKeys.count(); if (!pkTotal) return; @@ -661,16 +640,13 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e) // Find next const QShortcutEntry *current = 0, *next = 0; int i = 0, enabledShortcuts = 0; -#if defined(DEBUG_QSHORTCUTMAP) QVector<const QShortcutEntry*> ambiguousShortcuts; -#endif while(i < d->identicals.size()) { current = d->identicals.at(i); if (current->enabled || !next){ ++enabledShortcuts; -#if defined(DEBUG_QSHORTCUTMAP) - ambiguousShortcuts.append(current); -#endif + if (lcShortcutMap().isDebugEnabled()) + ambiguousShortcuts.append(current); if (enabledShortcuts > d->ambigCount + 1) break; next = current; @@ -683,19 +659,18 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e) if (!next || (e->isAutoRepeat() && !next->autorepeat)) return; // Dispatch next enabled -#if defined(DEBUG_QSHORTCUTMAP) - if (ambiguousShortcuts.size() > 1) { - qDebug() << "The following shortcuts are about to be activated ambiguously:"; - for (const QShortcutEntry *entry : qAsConst(ambiguousShortcuts)) { - qDebug().nospace() << "- " << entry->keyseq << " (belonging to " << entry->owner << ")"; + if (lcShortcutMap().isDebugEnabled()) { + if (ambiguousShortcuts.size() > 1) { + qCDebug(lcShortcutMap) << "The following shortcuts are about to be activated ambiguously:"; + for (const QShortcutEntry *entry : qAsConst(ambiguousShortcuts)) + qCDebug(lcShortcutMap).nospace() << "- " << entry->keyseq << " (belonging to " << entry->owner << ")"; } - } - qDebug().nospace() - << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\"" - << next->keyseq.toString() << "\", " << next->id << ", " - << (bool)(enabledShortcuts>1) << ") to object(" << next->owner << ')'; -#endif + qCDebug(lcShortcutMap).nospace() + << "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\"" + << next->keyseq.toString() << "\", " << next->id << ", " + << static_cast<bool>(enabledShortcuts>1) << ") to object(" << next->owner << ')'; + } QShortcutEvent se(next->keyseq, next->id, enabledShortcuts>1); QCoreApplication::sendEvent(const_cast<QObject *>(next->owner), &se); } diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index d3070a3d1a..803206477c 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -393,7 +393,7 @@ void QSimpleDrag::startDrag() static void sendDragLeave(QWindow *window) { - QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, 0, 0); + QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, { }, { }); } void QSimpleDrag::cancel() diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 238886220b..571b820409 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE class QSurfaceFormatPrivate { public: - explicit QSurfaceFormatPrivate(QSurfaceFormat::FormatOptions _opts = 0) + explicit QSurfaceFormatPrivate(QSurfaceFormat::FormatOptions _opts = { }) : ref(1) , opts(_opts) , redBufferSize(-1) diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp index 7aad4d8c7d..79da26f2ca 100644 --- a/src/gui/kernel/qtestsupport_gui.cpp +++ b/src/gui/kernel/qtestsupport_gui.cpp @@ -37,10 +37,15 @@ ** ****************************************************************************/ +#include <private/qguiapplication_p.h> + +#include <qpa/qplatformintegration.h> + #include "qtestsupport_gui.h" #include "qwindow.h" #include <QtCore/qtestsupport_core.h> +#include <QtCore/QDebug> QT_BEGIN_NAMESPACE @@ -55,6 +60,14 @@ QT_BEGIN_NAMESPACE */ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout) { + if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) { + qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window" + << "activation. This means there is an error in the test and it should either" + << "check for the WindowActivation platform capability before calling" + << "qWaitForWindowActivate, use qWaitForWindowExposed instead, or skip the test." + << "Falling back to qWaitForWindowExposed."; + return qWaitForWindowExposed(window, timeout); + } return QTest::qWaitFor([&]() { return window->isActive(); }, timeout); } diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp index 537097c09f..5ad16a8438 100644 --- a/src/gui/opengl/qopenglbuffer.cpp +++ b/src/gui/opengl/qopenglbuffer.cpp @@ -545,9 +545,9 @@ void *QOpenGLBuffer::map(QOpenGLBuffer::Access access) qWarning("QOpenGLBuffer::map(): buffer not created"); #endif if (!d->guard || !d->guard->id()) - return 0; + return nullptr; if (d->funcs->hasOpenGLExtension(QOpenGLExtensions::MapBufferRange)) { - QOpenGLBuffer::RangeAccessFlags rangeAccess = 0; + QOpenGLBuffer::RangeAccessFlags rangeAccess; switch (access) { case QOpenGLBuffer::ReadOnly: rangeAccess = QOpenGLBuffer::RangeRead; diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index bc3a4f7c1d..3e9eb3dd0a 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -493,7 +493,7 @@ QOpenGLFunctions::OpenGLFeatures QOpenGLFunctions::openGLFeatures() const { QOpenGLFunctionsPrivateEx *d = static_cast<QOpenGLFunctionsPrivateEx *>(d_ptr); if (!d) - return 0; + return { }; if (d->m_features == -1) d->m_features = qt_gl_resolve_features(); return QOpenGLFunctions::OpenGLFeatures(d->m_features); @@ -531,7 +531,7 @@ QOpenGLExtensions::OpenGLExtensions QOpenGLExtensions::openGLExtensions() { QOpenGLFunctionsPrivateEx *d = static_cast<QOpenGLFunctionsPrivateEx *>(d_ptr); if (!d) - return 0; + return { }; if (d->m_extensions == -1) d->m_extensions = qt_gl_resolve_extensions(); return QOpenGLExtensions::OpenGLExtensions(d->m_extensions); diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 47394999c6..20cc2b5ae5 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1575,7 +1575,7 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c case QImage::Format_ARGB32: case QImage::Format_RGBA64: d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc); - bindOption = 0; + bindOption = { }; break; case QImage::Format_Alpha8: if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) { diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 8314e8bc8a..722afaf119 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1061,7 +1061,7 @@ void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem) QFontEngine *fontEngine = staticTextItem->fontEngine(); fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions, - staticTextItem->numGlyphs, &path, 0); + staticTextItem->numGlyphs, &path, { }); if (!path.isEmpty()) { QPainterState *s = state(); QPainter::RenderHints oldHints = s->renderHints; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 3ce54c20be..d5cec1b45a 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5902,7 +5902,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(len); QFontEngine *fontEngine = d->state->font.d->engineForScript(QChar::Script_Common); - if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, 0)) + if (!fontEngine->stringToCMap(str.data(), len, &glyphs, &numGlyphs, { })) Q_UNREACHABLE(); QTextItemInt gf(glyphs, &d->state->font, str.data(), len, fontEngine); @@ -6404,7 +6404,7 @@ Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t } QFixed width = rightMost - leftMost; - QTextItem::RenderFlags flags = 0; + QTextItem::RenderFlags flags; if (font.underline()) flags |= QTextItem::Underline; @@ -7213,7 +7213,7 @@ QPainter::RenderHints QPainter::renderHints() const Q_D(const QPainter); if (!d->engine) - return 0; + return { }; return d->state->renderHints; } @@ -7786,16 +7786,9 @@ QPainterState::QPainterState(const QPainterState *s) } QPainterState::QPainterState() - : brushOrigin(0, 0), bgBrush(Qt::white), clipOperation(Qt::NoClip), - renderHints(0), - wx(0), wy(0), ww(0), wh(0), vx(0), vy(0), vw(0), vh(0), - opacity(1), WxF(false), VxF(false), clipEnabled(true), - bgMode(Qt::TransparentMode), painter(0), - layoutDirection(QGuiApplication::layoutDirection()), - composition_mode(QPainter::CompositionMode_SourceOver), - emulationSpecifier(0), changeFlags(0) + : brushOrigin(0, 0), WxF(false), VxF(false), clipEnabled(true), + layoutDirection(QGuiApplication::layoutDirection()) { - dirtyFlags = 0; } QPainterState::~QPainterState() @@ -7824,9 +7817,9 @@ void QPainterState::init(QPainter *p) { layoutDirection = QGuiApplication::layoutDirection(); composition_mode = QPainter::CompositionMode_SourceOver; emulationSpecifier = 0; - dirtyFlags = 0; + dirtyFlags = { }; changeFlags = 0; - renderHints = 0; + renderHints = { }; opacity = 1; } @@ -7883,7 +7876,7 @@ void QPainterState::init(QPainter *p) { /*! \fn void QPainter::drawImage(const QPointF &point, const QImage &image, const QRectF &source, - Qt::ImageConversionFlags flags = 0) + Qt::ImageConversionFlags flags = Qt::AutoColor) \overload @@ -7893,7 +7886,7 @@ void QPainterState::init(QPainter *p) { /*! \fn void QPainter::drawImage(const QPoint &point, const QImage &image, const QRect &source, - Qt::ImageConversionFlags flags = 0) + Qt::ImageConversionFlags flags = Qt::AutoColor) \overload Draws the rectangular portion \a source of the given \a image with diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 29d4880eb9..285bd90502 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -154,29 +154,29 @@ public: QFont deviceFont; QPen pen; QBrush brush; - QBrush bgBrush; // background brush + QBrush bgBrush = Qt::white; // background brush QRegion clipRegion; QPainterPath clipPath; - Qt::ClipOperation clipOperation; + Qt::ClipOperation clipOperation = Qt::NoClip; QPainter::RenderHints renderHints; QVector<QPainterClipInfo> clipInfo; // ### Make me smaller and faster to copy around... QTransform worldMatrix; // World transformation matrix, not window and viewport QTransform matrix; // Complete transformation matrix, QTransform redirectionMatrix; - int wx, wy, ww, wh; // window rectangle - int vx, vy, vw, vh; // viewport rectangle - qreal opacity; + int wx = 0, wy = 0, ww = 0, wh = 0; // window rectangle + int vx = 0, vy = 0, vw = 0, vh = 0; // viewport rectangle + qreal opacity = 1; uint WxF:1; // World transformation uint VxF:1; // View transformation uint clipEnabled:1; - Qt::BGMode bgMode; - QPainter *painter; + Qt::BGMode bgMode = Qt::TransparentMode; + QPainter *painter = nullptr; Qt::LayoutDirection layoutDirection; - QPainter::CompositionMode composition_mode; - uint emulationSpecifier; - uint changeFlags; + QPainter::CompositionMode composition_mode = QPainter::CompositionMode_SourceOver; + uint emulationSpecifier = 0; + uint changeFlags = 0; }; struct QPainterDummyState diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 1fb37ece56..859122c3b9 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1253,7 +1253,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString & fe->addOutlineToPath(x, y, glyphs, this, si.analysis.bidiLevel % 2 ? QTextItem::RenderFlags(QTextItem::RightToLeft) - : QTextItem::RenderFlags(0)); + : QTextItem::RenderFlags{}); const qreal lw = fe->lineThickness().toReal(); if (f.d->underline) { diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 45e90bd99b..0ecb4390e9 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -427,7 +427,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i origin = QOpenGLTextureBlitter::OriginBottomLeft; textureId = d_ptr->textureId; } else { - TextureFlags flags = 0; + TextureFlags flags; textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags); d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0; d_ptr->premultiplied = (flags & TexturePremultiplied) != 0; @@ -534,7 +534,7 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu GLuint pixelType = GL_UNSIGNED_BYTE; bool needsConversion = false; - *flags = 0; + *flags = { }; switch (image.format()) { case QImage::Format_ARGB32_Premultiplied: *flags |= TexturePremultiplied; diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h index 4f08b0092f..7aa054f1e2 100644 --- a/src/gui/painting/qplatformbackingstore.h +++ b/src/gui/painting/qplatformbackingstore.h @@ -100,7 +100,7 @@ public: bool isLocked() const; void appendTexture(void *source, GLuint textureId, const QRect &geometry, - const QRect &clipRect = QRect(), Flags flags = nullptr); + const QRect &clipRect = QRect(), Flags flags = { }); void clear(); Q_SIGNALS: diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 8ef98d2e42..ece5190ff7 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -48,8 +48,7 @@ #ifdef Q_OS_WIN #include "qrhid3d11_p_p.h" #endif -//#ifdef Q_OS_DARWIN -#ifdef Q_OS_MACOS +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) #include "qrhimetal_p_p.h" #endif @@ -2253,9 +2252,7 @@ bool QRhiTexture::buildFrom(const QRhiNativeHandles *src) \value Repeat \value ClampToEdge - \value Border \value Mirror - \value MirrorOnce */ /*! @@ -2322,6 +2319,24 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const } /*! + \fn bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const; + + \return true if the \a other QRhiRenderPassDescriptor is compatible with + this one, meaning \c this and \a other can be used interchangebly in + QRhiGraphicsPipeline::setRenderPassDescriptor(). + + The concept of the compatibility of renderpass descriptors is similar to + the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout + compatibility} of QRhiShaderResourceBindings instances. They allow better + reuse of QRhiGraphicsPipeline instances: for example, a + QRhiGraphicsPipeline instance cache is expected to use these functions to + look for a matching pipeline, instead of just comparing pointers, thus + allowing a different QRhiRenderPassDescriptor and + QRhiShaderResourceBindings to be used in combination with the pipeline, as + long as they are compatible. + */ + +/*! \return a pointer to a backend-specific QRhiNativeHandles subclass, such as QRhiVulkanRenderPassNativeHandles. The returned value is null when exposing the underlying native resources is not supported by the backend. @@ -4049,8 +4064,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh break; #endif case Metal: -//#ifdef Q_OS_DARWIN -#ifdef Q_OS_MACOS +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params), static_cast<QRhiMetalNativeHandles *>(importDevice)); break; diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 907924c788..9df2c58962 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -812,9 +812,7 @@ public: enum AddressMode { Repeat, ClampToEdge, - Border, Mirror, - MirrorOnce }; enum CompareOp { @@ -913,6 +911,7 @@ class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource public: QRhiResource::Type resourceType() const override; + virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0; virtual const QRhiNativeHandles *nativeHandles(); protected: diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 5e576e9c6a..52109edce0 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -2862,12 +2862,8 @@ static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMo return D3D11_TEXTURE_ADDRESS_WRAP; case QRhiSampler::ClampToEdge: return D3D11_TEXTURE_ADDRESS_CLAMP; - case QRhiSampler::Border: - return D3D11_TEXTURE_ADDRESS_BORDER; case QRhiSampler::Mirror: return D3D11_TEXTURE_ADDRESS_MIRROR; - case QRhiSampler::MirrorOnce: - return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE; default: Q_UNREACHABLE(); return D3D11_TEXTURE_ADDRESS_CLAMP; @@ -2944,6 +2940,12 @@ void QD3D11RenderPassDescriptor::release() // nothing to do here } +bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QD3D11ReferenceRenderTarget::QD3D11ReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 26de34ae0a..13c56b1d6d 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -136,6 +136,7 @@ struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor QD3D11RenderPassDescriptor(QRhiImplementation *rhi); ~QD3D11RenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QD3D11RenderTargetData diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index b394354787..b551980bb3 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1785,11 +1785,6 @@ static inline GLenum toGlWrapMode(QRhiSampler::AddressMode m) return GL_CLAMP_TO_EDGE; case QRhiSampler::Mirror: return GL_MIRRORED_REPEAT; - case QRhiSampler::MirrorOnce: - Q_FALLTHROUGH(); - case QRhiSampler::Border: - qWarning("Unsupported wrap mode %d", m); - return GL_CLAMP_TO_EDGE; default: Q_UNREACHABLE(); return GL_CLAMP_TO_EDGE; @@ -3459,6 +3454,12 @@ void QGles2RenderPassDescriptor::release() // nothing to do here } +bool QGles2RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QGles2ReferenceRenderTarget::QGles2ReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index cc945876e6..b0f5e340fb 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -185,6 +185,7 @@ struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor QGles2RenderPassDescriptor(QRhiImplementation *rhi); ~QGles2RenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QGles2RenderTargetData diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 131b2da802..e5af1cfab1 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -41,6 +41,8 @@ #ifdef Q_OS_MACOS #include <AppKit/AppKit.h> +#else +#include <UIKit/UIKit.h> #endif #include <Metal/Metal.h> @@ -318,7 +320,13 @@ struct QMetalComputePipelineData struct QMetalSwapChainData { + // The iOS simulator's headers mark CAMetalLayer as iOS 13.0+ only. + // (for real device SDKs it is 8.0+) +#ifdef TARGET_IPHONE_SIMULATOR + API_AVAILABLE(ios(13.0)) CAMetalLayer *layer = nullptr; +#else CAMetalLayer *layer = nullptr; +#endif id<CAMetalDrawable> curDrawable; dispatch_semaphore_t sem[QMTL_FRAMES_IN_FLIGHT]; MTLRenderPassDescriptor *rp = nullptr; @@ -1763,8 +1771,10 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD) if (changeEnd == -1 || u.offset + u.data.size() > changeEnd) changeEnd = u.offset + u.data.size(); } +#ifdef Q_OS_MACOS if (changeBegin >= 0 && bufD->d->managed) [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))]; +#endif bufD->d->pendingUpdates[idx].clear(); } @@ -1798,8 +1808,12 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb, if (color0.needsDrawableForTex || color0.needsDrawableForResolveTex) { Q_ASSERT(currentSwapChain); QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain); - if (!swapChainD->d->curDrawable) - swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable]; + if (!swapChainD->d->curDrawable) { +#ifdef TARGET_IPHONE_SIMULATOR + if (@available(ios 13.0, *)) +#endif + swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable]; + } if (!swapChainD->d->curDrawable) { qWarning("No drawable"); return; @@ -2170,12 +2184,13 @@ bool QMetalRenderBuffer::build() case DepthStencil: #ifdef Q_OS_MACOS desc.storageMode = MTLStorageModePrivate; + d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported + ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8; #else - desc.storageMode = MTLResourceStorageModeMemoryless; + desc.storageMode = MTLStorageModeMemoryless; transientBacking = true; + d->format = MTLPixelFormatDepth32Float_Stencil8; #endif - d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported - ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8; desc.pixelFormat = d->format; break; case Color: @@ -2569,12 +2584,8 @@ static inline MTLSamplerAddressMode toMetalAddressMode(QRhiSampler::AddressMode return MTLSamplerAddressModeRepeat; case QRhiSampler::ClampToEdge: return MTLSamplerAddressModeClampToEdge; - case QRhiSampler::Border: - return MTLSamplerAddressModeClampToBorderColor; case QRhiSampler::Mirror: return MTLSamplerAddressModeMirrorRepeat; - case QRhiSampler::MirrorOnce: - return MTLSamplerAddressModeMirrorClampToEdge; default: Q_UNREACHABLE(); return MTLSamplerAddressModeClampToEdge; @@ -2647,6 +2658,32 @@ void QMetalRenderPassDescriptor::release() // nothing to do here } +bool QMetalRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + if (!other) + return false; + + const QMetalRenderPassDescriptor *o = QRHI_RES(const QMetalRenderPassDescriptor, other); + + if (colorAttachmentCount != o->colorAttachmentCount) + return false; + + if (hasDepthStencil != o->hasDepthStencil) + return false; + + for (int i = 0; i < colorAttachmentCount; ++i) { + if (colorFormat[i] != o->colorFormat[i]) + return false; + } + + if (hasDepthStencil) { + if (dsFormat != o->dsFormat) + return false; + } + + return true; +} + QMetalReferenceRenderTarget::QMetalReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(new QMetalRenderTargetData) @@ -3311,7 +3348,11 @@ bool QMetalGraphicsPipeline::build() // validation blows up otherwise. MTLPixelFormat fmt = MTLPixelFormat(rpD->dsFormat); rpDesc.depthAttachmentPixelFormat = fmt; +#ifdef Q_OS_MACOS if (fmt != MTLPixelFormatDepth16Unorm && fmt != MTLPixelFormatDepth32Float) +#else + if (fmt != MTLPixelFormatDepth32Float) +#endif rpDesc.stencilAttachmentPixelFormat = fmt; } @@ -3528,6 +3569,10 @@ QMetalSwapChain::~QMetalSwapChain() void QMetalSwapChain::release() { +#ifdef TARGET_IPHONE_SIMULATOR + if (@available(ios 13.0, *)) { +#endif + if (!d->layer) return; @@ -3556,6 +3601,10 @@ void QMetalSwapChain::release() QRHI_PROF_F(releaseSwapChain(this)); rhiD->unregisterResource(this); + +#ifdef TARGET_IPHONE_SIMULATOR + } +#endif } QRhiCommandBuffer *QMetalSwapChain::currentFrameCommandBuffer() @@ -3578,16 +3627,20 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor() { chooseFormats(); // ensure colorFormat and similar are filled out - QRHI_RES_RHI(QRhiMetal); QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi); rpD->colorAttachmentCount = 1; rpD->hasDepthStencil = m_depthStencil != nullptr; rpD->colorFormat[0] = int(d->colorFormat); +#ifdef Q_OS_MACOS // m_depthStencil may not be built yet so cannot rely on computed fields in it + QRHI_RES_RHI(QRhiMetal); rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8; +#else + rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8; +#endif return rpD; } @@ -3603,6 +3656,10 @@ void QMetalSwapChain::chooseFormats() bool QMetalSwapChain::buildOrResize() { +#ifdef TARGET_IPHONE_SIMULATOR + if (@available(ios 13.0, *)) { +#endif + Q_ASSERT(m_window); const bool needsRegistration = !window || window != m_window; @@ -3622,7 +3679,11 @@ bool QMetalSwapChain::buildOrResize() return false; } +#ifdef Q_OS_MACOS NSView *view = reinterpret_cast<NSView *>(window->winId()); +#else + UIView *view = reinterpret_cast<UIView *>(window->winId()); +#endif Q_ASSERT(view); d->layer = static_cast<CAMetalLayer *>(view.layer); Q_ASSERT(d->layer); @@ -3726,6 +3787,15 @@ bool QMetalSwapChain::buildOrResize() rhiD->registerResource(this); return true; + +#ifdef TARGET_IPHONE_SIMULATOR + } else { + // Won't ever get here in a normal app because MTLDevice creation would + // fail too. Print a warning, just in case. + qWarning("No CAMetalLayer support in this version of the iOS Simulator"); + return false; + } +#endif } QT_END_NAMESPACE diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 2be86db5c8..7876539fcd 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -138,6 +138,7 @@ struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor QMetalRenderPassDescriptor(QRhiImplementation *rhi); ~QMetalRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass() diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index fe606f971f..0baea1b9d6 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -690,6 +690,12 @@ void QNullRenderPassDescriptor::release() { } +bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + Q_UNUSED(other); + return true; +} + QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi) : QRhiRenderTarget(rhi), d(rhi) diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index ce517bfa63..c96f279f7d 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -101,6 +101,7 @@ struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor QNullRenderPassDescriptor(QRhiImplementation *rhi); ~QNullRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; }; struct QNullRenderTargetData diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index a200a6e271..49ca2326bc 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -1032,54 +1032,62 @@ VkFormat QRhiVulkan::optimalDepthStencilFormat() return optimalDsFormat; } -bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat) +bool QRhiVulkan::createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat) { - VkAttachmentDescription attDesc[3]; - memset(attDesc, 0, sizeof(attDesc)); - // attachment list layout is color (1), ds (0-1), resolve (0-1) - attDesc[0].format = colorFormat; - attDesc[0].samples = samples; - attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[0].storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; - attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[0].finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - // clear on load + no store + lazy alloc + transient image should play - // nicely with tiled GPUs (no physical backing necessary for ds buffer) - attDesc[1].format = optimalDepthStencilFormat(); - attDesc[1].samples = samples; - attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + VkAttachmentDescription attDesc; + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = colorFormat; + attDesc.samples = samples; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->attDescs.append(attDesc); - if (samples > VK_SAMPLE_COUNT_1_BIT) { - attDesc[2].format = colorFormat; - attDesc[2].samples = VK_SAMPLE_COUNT_1_BIT; - attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attDesc[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }); + + if (hasDepthStencil) { + // clear on load + no store + lazy alloc + transient image should play + // nicely with tiled GPUs (no physical backing necessary for ds buffer) + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = optimalDepthStencilFormat(); + attDesc.samples = samples; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + rpD->attDescs.append(attDesc); + + rpD->dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; } - VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - VkAttachmentReference resolveRef = { 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + if (samples > VK_SAMPLE_COUNT_1_BIT) { + memset(&attDesc, 0, sizeof(attDesc)); + attDesc.format = colorFormat; + attDesc.samples = VK_SAMPLE_COUNT_1_BIT; + attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + rpD->attDescs.append(attDesc); + + rpD->resolveRefs.append({ 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }); + } VkSubpassDescription subpassDesc; memset(&subpassDesc, 0, sizeof(subpassDesc)); subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDesc.colorAttachmentCount = 1; - subpassDesc.pColorAttachments = &colorRef; - subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr; + subpassDesc.pColorAttachments = rpD->colorRefs.constData(); + subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &rpD->dsRef : nullptr; // Replace the first implicit dep (TOP_OF_PIPE / ALL_COMMANDS) with our own. VkSubpassDependency subpassDep; @@ -1095,7 +1103,7 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, memset(&rpInfo, 0, sizeof(rpInfo)); rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; rpInfo.attachmentCount = 1; - rpInfo.pAttachments = attDesc; + rpInfo.pAttachments = rpD->attDescs.constData(); rpInfo.subpassCount = 1; rpInfo.pSubpasses = &subpassDesc; rpInfo.dependencyCount = 1; @@ -1106,19 +1114,21 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, if (samples > VK_SAMPLE_COUNT_1_BIT) { rpInfo.attachmentCount += 1; - subpassDesc.pResolveAttachments = &resolveRef; + subpassDesc.pResolveAttachments = rpD->resolveRefs.constData(); } - VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp); + VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp); if (err != VK_SUCCESS) { qWarning("Failed to create renderpass: %d", err); return false; } + rpD->hasDepthStencil = hasDepthStencil; + return true; } -bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, +bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *firstColorAttachment, const QRhiColorAttachment *lastColorAttachment, bool preserveColor, @@ -1126,10 +1136,6 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, QRhiRenderBuffer *depthStencilBuffer, QRhiTexture *depthTexture) { - QVarLengthArray<VkAttachmentDescription, 8> attDescs; - QVarLengthArray<VkAttachmentReference, 8> colorRefs; - QVarLengthArray<VkAttachmentReference, 8> resolveRefs; - // attachment list layout is color (0-8), ds (0-1), resolve (0-8) for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { @@ -1150,14 +1156,14 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, // this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); - const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - colorRefs.append(ref); + const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + rpD->colorRefs.append(ref); } - const bool hasDepthStencil = depthStencilBuffer || depthTexture; - if (hasDepthStencil) { + rpD->hasDepthStencil = depthStencilBuffer || depthTexture; + if (rpD->hasDepthStencil) { const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->vkformat : QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat; const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples @@ -1174,9 +1180,9 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, attDesc.stencilStoreOp = storeOp; attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); } - VkAttachmentReference dsRef = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; + rpD->dsRef = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) { if (it->resolveTexture()) { @@ -1194,37 +1200,37 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp, attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attDescs.append(attDesc); + rpD->attDescs.append(attDesc); - const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - resolveRefs.append(ref); + const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + rpD->resolveRefs.append(ref); } else { const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - resolveRefs.append(ref); + rpD->resolveRefs.append(ref); } } VkSubpassDescription subpassDesc; memset(&subpassDesc, 0, sizeof(subpassDesc)); subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = uint32_t(colorRefs.count()); - Q_ASSERT(colorRefs.count() == resolveRefs.count()); - subpassDesc.pColorAttachments = !colorRefs.isEmpty() ? colorRefs.constData() : nullptr; - subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr; - subpassDesc.pResolveAttachments = !resolveRefs.isEmpty() ? resolveRefs.constData() : nullptr; + subpassDesc.colorAttachmentCount = uint32_t(rpD->colorRefs.count()); + Q_ASSERT(rpD->colorRefs.count() == rpD->resolveRefs.count()); + subpassDesc.pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() : nullptr; + subpassDesc.pDepthStencilAttachment = rpD->hasDepthStencil ? &rpD->dsRef : nullptr; + subpassDesc.pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() : nullptr; VkRenderPassCreateInfo rpInfo; memset(&rpInfo, 0, sizeof(rpInfo)); rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpInfo.attachmentCount = uint32_t(attDescs.count()); - rpInfo.pAttachments = attDescs.constData(); + rpInfo.attachmentCount = uint32_t(rpD->attDescs.count()); + rpInfo.pAttachments = rpD->attDescs.constData(); rpInfo.subpassCount = 1; rpInfo.pSubpasses = &subpassDesc; // don't yet know the correct initial/final access and stage stuff for the // implicit deps at this point, so leave it to the resource tracking to // generate barriers - VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp); + VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp); if (err != VK_SUCCESS) { qWarning("Failed to create renderpass: %d", err); return false; @@ -1710,6 +1716,10 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram presInfo.waitSemaphoreCount = 1; presInfo.pWaitSemaphores = &frame.drawSem; // gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem; + // Do platform-specific WM notification. F.ex. essential on Wayland in + // order to circumvent driver frame callbacks + inst->presentAboutToBeQueued(swapChainD->window); + VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo); if (err != VK_SUCCESS) { if (err == VK_ERROR_OUT_OF_DATE_KHR) { @@ -4613,12 +4623,8 @@ static inline VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m) return VK_SAMPLER_ADDRESS_MODE_REPEAT; case QRhiSampler::ClampToEdge: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - case QRhiSampler::Border: - return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; case QRhiSampler::Mirror: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - case QRhiSampler::MirrorOnce: - return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE; default: Q_UNREACHABLE(); return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -5501,6 +5507,61 @@ void QVkRenderPassDescriptor::release() rhiD->unregisterResource(this); } +static inline bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b) +{ + return a.format == b.format + && a.samples == b.samples + && a.loadOp == b.loadOp + && a.storeOp == b.storeOp + && a.stencilLoadOp == b.stencilLoadOp + && a.stencilStoreOp == b.stencilStoreOp + && a.initialLayout == b.initialLayout + && a.finalLayout == b.finalLayout; +} + +bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const +{ + if (!other) + return false; + + const QVkRenderPassDescriptor *o = QRHI_RES(const QVkRenderPassDescriptor, other); + + if (attDescs.count() != o->attDescs.count()) + return false; + if (colorRefs.count() != o->colorRefs.count()) + return false; + if (resolveRefs.count() != o->resolveRefs.count()) + return false; + if (hasDepthStencil != o->hasDepthStencil) + return false; + + for (int i = 0, ie = colorRefs.count(); i != ie; ++i) { + const uint32_t attIdx = colorRefs[i].attachment; + if (attIdx != o->colorRefs[i].attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + if (hasDepthStencil) { + const uint32_t attIdx = dsRef.attachment; + if (attIdx != o->dsRef.attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + for (int i = 0, ie = resolveRefs.count(); i != ie; ++i) { + const uint32_t attIdx = resolveRefs[i].attachment; + if (attIdx != o->resolveRefs[i].attachment) + return false; + if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx])) + return false; + } + + return true; +} + const QRhiNativeHandles *QVkRenderPassDescriptor::nativeHandles() { nativeHandlesStruct.renderPass = rp; @@ -5584,7 +5645,7 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip QRHI_RES_RHI(QRhiVulkan); QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi); - if (!rhiD->createOffscreenRenderPass(&rp->rp, + if (!rhiD->createOffscreenRenderPass(rp, m_desc.cbeginColorAttachments(), m_desc.cendColorAttachments(), m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents), @@ -6285,7 +6346,7 @@ QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor() QRHI_RES_RHI(QRhiVulkan); QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi); - if (!rhiD->createDefaultRenderPass(&rp->rp, + if (!rhiD->createDefaultRenderPass(rp, m_depthStencil != nullptr, samples, colorFormat)) diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d0e1e6758b..ffa8c59ed5 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -171,10 +171,16 @@ struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor QVkRenderPassDescriptor(QRhiImplementation *rhi); ~QVkRenderPassDescriptor(); void release() override; + bool isCompatible(const QRhiRenderPassDescriptor *other) const override; const QRhiNativeHandles *nativeHandles() override; VkRenderPass rp = VK_NULL_HANDLE; bool ownsRp = false; + QVarLengthArray<VkAttachmentDescription, 8> attDescs; + QVarLengthArray<VkAttachmentReference, 8> colorRefs; + QVarLengthArray<VkAttachmentReference, 8> resolveRefs; + bool hasDepthStencil = false; + VkAttachmentReference dsRef; QRhiVulkanRenderPassNativeHandles nativeHandlesStruct; int lastActiveFrameSlot = -1; }; @@ -727,11 +733,11 @@ public: VkFormat optimalDepthStencilFormat(); VkSampleCountFlagBits effectiveSampleCount(int sampleCount); - bool createDefaultRenderPass(VkRenderPass *rp, + bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat); - bool createOffscreenRenderPass(VkRenderPass *rp, + bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD, const QRhiColorAttachment *firstColorAttachment, const QRhiColorAttachment *lastColorAttachment, bool preserveColor, diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp index 9d35d83336..dc6060f882 100644 --- a/src/gui/rhi/qshader.cpp +++ b/src/gui/rhi/qshader.cpp @@ -214,9 +214,6 @@ QT_BEGIN_NAMESPACE QShader, it indicates no shader code was found for the requested key. */ -static const int QSB_VERSION = 2; -static const int QSB_VERSION_WITHOUT_BINDINGS = 1; - /*! Constructs a new, empty (and thus invalid) QShader instance. */ @@ -368,9 +365,9 @@ QByteArray QShader::serialized() const if (!buf.open(QIODevice::WriteOnly)) return QByteArray(); - ds << QSB_VERSION; + ds << QShaderPrivate::QSB_VERSION; ds << int(d->stage); - ds << d->desc.toBinaryJson(); + ds << d->desc.toCbor(); ds << d->shaders.count(); for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) { const QShaderKey &k(it.key()); @@ -429,9 +426,12 @@ QShader QShader::fromSerialized(const QByteArray &data) Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached int intVal; ds >> intVal; - const int qsbVersion = intVal; - if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { - qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion); + d->qsbVersion = intVal; + if (d->qsbVersion != QShaderPrivate::QSB_VERSION + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON + && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) + { + qWarning("Attempted to deserialize QShader with unknown version %d.", d->qsbVersion); return QShader(); } @@ -439,7 +439,10 @@ QShader QShader::fromSerialized(const QByteArray &data) d->stage = Stage(intVal); QByteArray descBin; ds >> descBin; - d->desc = QShaderDescription::fromBinaryJson(descBin); + if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) + d->desc = QShaderDescription::fromCbor(descBin); + else + d->desc = QShaderDescription::fromBinaryJson(descBin); int count; ds >> count; for (int i = 0; i < count; ++i) { @@ -454,7 +457,7 @@ QShader QShader::fromSerialized(const QByteArray &data) d->shaders[k] = shader; } - if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) { + if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) { ds >> count; for (int i = 0; i < count; ++i) { QShaderKey k; diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h index 4535e01491..8c89f2b45f 100644 --- a/src/gui/rhi/qshader_p_p.h +++ b/src/gui/rhi/qshader_p_p.h @@ -57,6 +57,10 @@ QT_BEGIN_NAMESPACE struct Q_GUI_EXPORT QShaderPrivate { + static const int QSB_VERSION = 3; + static const int QSB_VERSION_WITH_BINARY_JSON = 2; + static const int QSB_VERSION_WITHOUT_BINDINGS = 1; + QShaderPrivate() : ref(1) { @@ -64,6 +68,7 @@ struct Q_GUI_EXPORT QShaderPrivate QShaderPrivate(const QShaderPrivate *other) : ref(1), + qsbVersion(other->qsbVersion), stage(other->stage), desc(other->desc), shaders(other->shaders), @@ -75,6 +80,7 @@ struct Q_GUI_EXPORT QShaderPrivate static const QShaderPrivate *get(const QShader *s) { return s->d; } QAtomicInt ref; + int qsbVersion = QSB_VERSION; QShader::Stage stage = QShader::VertexStage; QShaderDescription desc; QHash<QShaderKey, QShaderCode> shaders; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index 179d5f3a07..d0f73f6aa7 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -38,6 +38,9 @@ #include <QDebug> #include <QJsonObject> #include <QJsonArray> +#include <QCborValue> +#include <QCborMap> +#include <QCborArray> QT_BEGIN_NAMESPACE @@ -335,11 +338,27 @@ bool QShaderDescription::isValid() const /*! \return a serialized binary version of the data. - \sa toJson() + \sa toJson(), toCbor() */ QByteArray QShaderDescription::toBinaryJson() const { +#if QT_CONFIG(binaryjson) return d->makeDoc().toBinaryData(); +#else + qWarning("Cannot generate binary JSON from QShaderDescription due to disabled binaryjson feature"); + return QByteArray(); +#endif +} + +/*! + \return a serialized binary version of the data in CBOR (Concise Binary + Object Representation) format. + + \sa QCborValue, toBinaryJson(), toJson() + */ +QByteArray QShaderDescription::toCbor() const +{ + return QCborValue::fromJsonValue(d->makeDoc().object()).toCbor(); } /*! @@ -347,7 +366,7 @@ QByteArray QShaderDescription::toBinaryJson() const \note There is no deserialization method provided for JSON text. - \sa toBinaryJson() + \sa toBinaryJson(), toCbor() */ QByteArray QShaderDescription::toJson() const { @@ -357,11 +376,38 @@ QByteArray QShaderDescription::toJson() const /*! Deserializes the given binary JSON \a data and returns a new QShaderDescription. + + \sa fromCbor() */ QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data) { QShaderDescription desc; +#if QT_CONFIG(binaryjson) QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data)); +#else + Q_UNUSED(data); + qWarning("Cannot load QShaderDescription from binary JSON due to disabled binaryjson feature"); +#endif + return desc; +} + +/*! + Deserializes the given CBOR \a data and returns a new QShaderDescription. + + \sa fromBinaryJson() + */ +QShaderDescription QShaderDescription::fromCbor(const QByteArray &data) +{ + QShaderDescription desc; + const QCborValue cbor = QCborValue::fromCbor(data); + if (cbor.isMap()) { + const QJsonDocument doc(cbor.toMap().toJsonObject()); + QShaderDescriptionPrivate::get(&desc)->loadDoc(doc); + } + if (cbor.isArray()) { + const QJsonDocument doc(cbor.toArray().toJsonArray()); + QShaderDescriptionPrivate::get(&desc)->loadDoc(doc); + } return desc; } @@ -1119,4 +1165,106 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc) } } +/*! + Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription + */ +bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW +{ + if (lhs.d == rhs.d) + return true; + + return lhs.d->inVars == rhs.d->inVars + && lhs.d->outVars == rhs.d->outVars + && lhs.d->uniformBlocks == rhs.d->uniformBlocks + && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks + && lhs.d->storageBlocks == rhs.d->storageBlocks + && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers + && lhs.d->storageImages == rhs.d->storageImages + && lhs.d->localSize == rhs.d->localSize; +} + +/*! + Returns \c true if the two InOutVariable objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::InOutVariable + */ +bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.type == rhs.type + && lhs.location == rhs.location + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.imageFormat == rhs.imageFormat + && lhs.imageFlags == rhs.imageFlags; +} + +/*! + Returns \c true if the two BlockVariable objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::BlockVariable + */ +bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.type == rhs.type + && lhs.offset == rhs.offset + && lhs.size == rhs.size + && lhs.arrayDims == rhs.arrayDims + && lhs.arrayStride == rhs.arrayStride + && lhs.matrixStride == rhs.matrixStride + && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor + && lhs.structMembers == rhs.structMembers; +} + +/*! + Returns \c true if the two UniformBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::UniformBlock + */ +bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.blockName == rhs.blockName + && lhs.structName == rhs.structName + && lhs.size == rhs.size + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.members == rhs.members; +} + +/*! + Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::PushConstantBlock + */ +bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.name == rhs.name + && lhs.size == rhs.size + && lhs.members == rhs.members; +} + +/*! + Returns \c true if the two StorageBlock objects \a lhs and \a rhs are + equal. + + \relates QShaderDescription::StorageBlock + */ +bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW +{ + return lhs.blockName == rhs.blockName + && lhs.instanceName == rhs.instanceName + && lhs.knownSize == rhs.knownSize + && lhs.binding == rhs.binding + && lhs.descriptorSet == rhs.descriptorSet + && lhs.members == rhs.members; +} + QT_END_NAMESPACE diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 5a63b998cd..e02a53dcb5 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -69,9 +69,11 @@ public: bool isValid() const; QByteArray toBinaryJson() const; + QByteArray toCbor() const; QByteArray toJson() const; static QShaderDescription fromBinaryJson(const QByteArray &data); + static QShaderDescription fromCbor(const QByteArray &data); enum VariableType { Unknown = 0, @@ -263,6 +265,7 @@ private: #ifndef QT_NO_DEBUG_STREAM friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &); #endif + friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags) @@ -276,6 +279,43 @@ Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlo Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &); #endif +Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW; +Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW; + +inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + +inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW +{ + return !(lhs == rhs); +} + QT_END_NAMESPACE #endif diff --git a/src/gui/rhi/rhi.pri b/src/gui/rhi/rhi.pri index 4297a5602b..ccd9592634 100644 --- a/src/gui/rhi/rhi.pri +++ b/src/gui/rhi/rhi.pri @@ -43,15 +43,15 @@ win32 { LIBS += -ld3d11 -ldxgi -ldxguid } -# darwin { -macos { +macos|ios { HEADERS += \ rhi/qrhimetal_p.h \ rhi/qrhimetal_p_p.h SOURCES += \ rhi/qrhimetal.mm - LIBS += -framework AppKit -framework Metal + macos: LIBS += -framework AppKit + LIBS += -framework Metal } include($$PWD/../../3rdparty/VulkanMemoryAllocator.pri) diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index ce7c7610c1..cf3d8e5ea2 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -123,6 +123,7 @@ static const QCssKnownValue properties[NumProperties - 1] = { { "font-variant", FontVariant }, { "font-weight", FontWeight }, { "height", Height }, + { "icon", QtIcon }, { "image", QtImage }, { "image-position", QtImageAlignment }, { "left", Left }, @@ -681,7 +682,7 @@ bool ValueExtractor::extractOutline(int *borders, QBrush *colors, BorderStyle *s static Qt::Alignment parseAlignment(const QCss::Value *values, int count) { - Qt::Alignment a[2] = { 0, 0 }; + Qt::Alignment a[2] = { { }, { } }; for (int i = 0; i < qMin(2, count); i++) { if (values[i].type != Value::KnownIdentifier) break; @@ -1379,6 +1380,37 @@ bool ValueExtractor::extractImage(QIcon *icon, Qt::Alignment *a, QSize *size) return hit; } +bool ValueExtractor::extractIcon(QIcon *icon, QSize *size) +{ + // Find last declaration that specifies an icon + const auto declaration = std::find_if( + declarations.rbegin(), declarations.rend(), + [](const Declaration &decl) { return decl.d->propertyId == QtIcon; }); + if (declaration == declarations.rend()) + return false; + + *icon = declaration->iconValue(); + + // If the value contains a URI, try to get the size of the icon + if (declaration->d->values.isEmpty()) + return true; + + const auto &propertyValue = declaration->d->values.constFirst(); + if (propertyValue.type != Value::Uri) + return true; + + // First try to read just the size from the image without loading it + const QString url(propertyValue.variant.toString()); + QImageReader imageReader(url); + *size = imageReader.size(); + if (!size->isNull()) + return true; + + // Get the size by loading the image instead + *size = imageReader.read().size(); + return true; +} + /////////////////////////////////////////////////////////////////////////////// // Declaration QColor Declaration::colorValue(const QPalette &pal) const diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index ab85e76cf3..b8bf259dda 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -198,6 +198,7 @@ enum Property { QtLineHeightType, FontKerning, QtForegroundTextureCacheKey, + QtIcon, NumProperties }; @@ -855,6 +856,7 @@ struct Q_GUI_EXPORT ValueExtractor bool extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg); int extractStyleFeatures(); bool extractImage(QIcon *icon, Qt::Alignment *a, QSize *size); + bool extractIcon(QIcon *icon, QSize *size); int lengthValue(const Declaration &decl); diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index d8a971c7b7..89f943ca51 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -952,7 +952,7 @@ void QDistanceField::setGlyph(QFontEngine *fontEngine, glyph_t glyph, bool doubl { QFixedPoint position; QPainterPath path; - fontEngine->addGlyphsToPath(&glyph, &position, 1, &path, 0); + fontEngine->addGlyphsToPath(&glyph, &position, 1, &path, { }); path.translate(-path.boundingRect().topLeft()); path.setFillRule(Qt::WindingFill); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 403a0510fa..1668fac5a3 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -141,7 +141,7 @@ static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGl qglyphs.glyphs = const_cast<glyph_t *>(glyphs); qglyphs.advances = reinterpret_cast<QFixed *>(advances); - fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0)); + fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{}); } static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length) @@ -506,7 +506,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform g.numGlyphs = 1; g.glyphs = &kashidaGlyph; g.advances = &kashidaWidth; - recalcAdvances(&g, 0); + recalcAdvances(&g, { }); for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) { xpos -= kashidaWidth; @@ -948,7 +948,7 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph) im.fill(Qt::transparent); QPainter p(&im); p.setRenderHint(QPainter::Antialiasing); - addGlyphsToPath(&glyph, &pt, 1, &path, 0); + addGlyphsToPath(&glyph, &pt, 1, &path, { }); p.setPen(Qt::NoPen); p.setBrush(Qt::black); p.drawPath(path); diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index d3e4f11e8c..906047cdb4 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -562,7 +562,7 @@ int QFontMetrics::width(const QString &text, int len, int flags) const int numGlyphs = len; QVarLengthGlyphLayoutArray glyphs(numGlyphs); QFontEngine *engine = d->engineForScript(QChar::Script_Common); - if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) + if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, { })) Q_UNREACHABLE(); QFixed width; @@ -684,7 +684,7 @@ int QFontMetrics::horizontalAdvance(QChar ch) const glyphs.numGlyphs = 1; glyphs.glyphs = &glyph; glyphs.advances = &advance; - engine->recalcAdvances(&glyphs, 0); + engine->recalcAdvances(&glyphs, { }); return qRound(advance); } @@ -736,7 +736,7 @@ int QFontMetrics::charWidth(const QString &text, int pos) const glyphs.numGlyphs = 1; glyphs.glyphs = &glyph; glyphs.advances = &advance; - engine->recalcAdvances(&glyphs, 0); + engine->recalcAdvances(&glyphs, { }); width = qRound(advance); } @@ -1619,7 +1619,7 @@ qreal QFontMetricsF::horizontalAdvance(QChar ch) const glyphs.numGlyphs = 1; glyphs.glyphs = &glyph; glyphs.advances = &advance; - engine->recalcAdvances(&glyphs, 0); + engine->recalcAdvances(&glyphs, { }); return advance.toReal(); } diff --git a/src/gui/text/qglyphrun.cpp b/src/gui/text/qglyphrun.cpp index 3c16c3bf62..f4cd839f15 100644 --- a/src/gui/text/qglyphrun.cpp +++ b/src/gui/text/qglyphrun.cpp @@ -279,7 +279,7 @@ void QGlyphRun::clear() { detach(); d->rawFont = QRawFont(); - d->flags = 0; + d->flags = { }; setPositions(QVector<QPointF>()); setGlyphIndexes(QVector<quint32>()); diff --git a/src/gui/text/qglyphrun_p.h b/src/gui/text/qglyphrun_p.h index 465c3c7000..46e2a8bbfb 100644 --- a/src/gui/text/qglyphrun_p.h +++ b/src/gui/text/qglyphrun_p.h @@ -65,8 +65,7 @@ class QGlyphRunPrivate: public QSharedData { public: QGlyphRunPrivate() - : flags(nullptr) - , glyphIndexData(glyphIndexes.constData()) + : glyphIndexData(glyphIndexes.constData()) , glyphIndexDataSize(0) , glyphPositionData(glyphPositions.constData()) , glyphPositionDataSize(0) diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index 2f25aea92b..397e6cc49f 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Copyright (C) 2013 Konstantin Ritt ** Contact: https://www.qt.io/licensing/ ** @@ -216,7 +216,20 @@ static const hb_script_t _qtscript_to_hbscript[] = { HB_SCRIPT_MASARAM_GONDI, HB_SCRIPT_NUSHU, HB_SCRIPT_SOYOMBO, - HB_SCRIPT_ZANABAZAR_SQUARE + HB_SCRIPT_ZANABAZAR_SQUARE, + + // Unicode 12.1 additions (not present in harfbuzz-ng 1.7.4) + hb_script_t(HB_TAG('D', 'o', 'g', 'r')), // Script_Dogra + hb_script_t(HB_TAG('G', 'o', 'n', 'g')), // Script_GunjalaGondi + hb_script_t(HB_TAG('R', 'o', 'h', 'g')), // Script_HanifiRohingya + hb_script_t(HB_TAG('M', 'a', 'k', 'a')), // Script_Makasar + hb_script_t(HB_TAG('M', 'e', 'd', 'f')), // Script_Medefaidrin + hb_script_t(HB_TAG('S', 'o', 'g', 'o')), // Script_OldSogdian + hb_script_t(HB_TAG('S', 'o', 'g', 'd')), // Script_Sogdian + hb_script_t(HB_TAG('E', 'l', 'y', 'm')), // Script_Elymaic + hb_script_t(HB_TAG('N', 'a', 'n', 'd')), // Script_Nandinagari + hb_script_t(HB_TAG('H', 'm', 'n', 'p')), // Script_NyiakengPuachueHmong + hb_script_t(HB_TAG('W', 'c', 'h', 'o')), // Script_Wancho }; Q_STATIC_ASSERT(QChar::ScriptCount == sizeof(_qtscript_to_hbscript) / sizeof(_qtscript_to_hbscript[0])); @@ -682,12 +695,12 @@ _hb_qt_font_create(QFontEngine *fe) return NULL; } - const int y_ppem = fe->fontDef.pixelSize; - const int x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100; + const qreal y_ppem = fe->fontDef.pixelSize; + const qreal x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100.0; hb_font_set_funcs(font, hb_qt_get_font_funcs(), (void *)fe, NULL); - hb_font_set_scale(font, QFixed(x_ppem).value(), -QFixed(y_ppem).value()); - hb_font_set_ppem(font, x_ppem, y_ppem); + hb_font_set_scale(font, QFixed::fromReal(x_ppem).value(), -QFixed::fromReal(y_ppem).value()); + hb_font_set_ppem(font, int(x_ppem), int(y_ppem)); hb_font_set_ptem(font, fe->fontDef.pointSize); diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index a060448924..e04c8909f3 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -303,7 +303,7 @@ QPainterPath QRawFont::pathForGlyph(quint32 glyphIndex) const QFixedPoint position; QPainterPath path; - d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, 0); + d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, { }); return path; } diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index a1b1c2e92b..2f02f62a57 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -243,7 +243,7 @@ void QTextDocumentPrivate::clear() curs->adjusted_anchor = 0; } - QList<QTextCursorPrivate *>oldCursors = cursors; + QSet<QTextCursorPrivate *> oldCursors = cursors; QT_TRY{ cursors.clear(); diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index f4e7a25f22..94c67b3264 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -277,8 +277,8 @@ private: public: void documentChange(int from, int length); - inline void addCursor(QTextCursorPrivate *c) { cursors.append(c); } - inline void removeCursor(QTextCursorPrivate *c) { cursors.removeAll(c); } + inline void addCursor(QTextCursorPrivate *c) { cursors.insert(c); } + inline void removeCursor(QTextCursorPrivate *c) { cursors.remove(c); } QTextFrame *frameAt(int pos) const; QTextFrame *rootFrame() const; @@ -330,7 +330,7 @@ private: BlockMap blocks; int initialBlockCharFormatIndex; - QList<QTextCursorPrivate *> cursors; + QSet<QTextCursorPrivate *> cursors; QMap<int, QTextObject *> objects; QMap<QUrl, QVariant> resources; QMap<QUrl, QVariant> cachedResources; diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 209433dac5..8a91b34b7a 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1720,7 +1720,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, g.glyphs[i] = actualFontEngine->glyphIndex('-'); if (Q_LIKELY(g.glyphs[i] != 0)) { QGlyphLayout tmp = g.mid(i, 1); - actualFontEngine->recalcAdvances(&tmp, 0); + actualFontEngine->recalcAdvances(&tmp, { }); } g.attributes[i].dontPrint = true; } @@ -1896,7 +1896,7 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri } if (kerningEnabled && !shaper_item.kerning_applied) - actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0)); + actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{}); if (engineIdx != 0) { for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) @@ -2581,7 +2581,7 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, g.numGlyphs = 1; g.glyphs = &kashidaGlyph; g.advances = &point->kashidaWidth; - fe->recalcAdvances(&g, 0); + fe->recalcAdvances(&g, { }); if (point->kashidaWidth == 0) point->type = Justification_Prohibited; @@ -3214,13 +3214,13 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int glyphs.advances = &ellipsisWidth; if (glyph != 0) { - engine->recalcAdvances(&glyphs, 0); + engine->recalcAdvances(&glyphs, { }); ellipsisText = ellipsisChar; } else { glyph = engine->glyphIndex('.'); if (glyph != 0) { - engine->recalcAdvances(&glyphs, 0); + engine->recalcAdvances(&glyphs, { }); ellipsisWidth *= 3; ellipsisText = QStringLiteral("..."); @@ -3895,12 +3895,7 @@ QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) } QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format) - : justified(false), - underlineStyle(QTextCharFormat::NoUnderline), - charFormat(format), - num_chars(0), - chars(nullptr), - logClusters(nullptr), + : charFormat(format), f(font), fontEngine(font->d->engineForScript(si.analysis.script)) { @@ -3910,13 +3905,9 @@ QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFo } QTextItemInt::QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars_, int numChars, QFontEngine *fe, const QTextCharFormat &format) - : flags(0), - justified(false), - underlineStyle(QTextCharFormat::NoUnderline), - charFormat(format), + : charFormat(format), num_chars(numChars), chars(chars_), - logClusters(nullptr), f(font), glyphs(g), fontEngine(fe) @@ -3928,7 +3919,7 @@ void QTextItemInt::initWithScriptItem(const QScriptItem &si) { // explicitly initialize flags so that initFontAttributes can be called // multiple times on the same TextItem - flags = 0; + flags = { }; if (si.analysis.bidiLevel %2) flags |= QTextItem::RightToLeft; ascent = si.ascent; diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 76b9757eba..f069951ce5 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -303,10 +303,7 @@ struct QScriptItem; class QTextItemInt : public QTextItem { public: - inline QTextItemInt() - : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(nullptr), - logClusters(nullptr), f(nullptr), fontEngine(nullptr) - {} + inline QTextItemInt() = default; QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat()); QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe, const QTextCharFormat &format = QTextCharFormat()); @@ -321,16 +318,16 @@ public: QFixed width; RenderFlags flags; - bool justified; - QTextCharFormat::UnderlineStyle underlineStyle; + bool justified = false; + QTextCharFormat::UnderlineStyle underlineStyle = QTextCharFormat::NoUnderline; const QTextCharFormat charFormat; - int num_chars; - const QChar *chars; - const unsigned short *logClusters; - const QFont *f; + int num_chars = 0; + const QChar *chars = nullptr; + const unsigned short *logClusters = nullptr; + const QFont *f = nullptr; QGlyphLayout glyphs; - QFontEngine *fontEngine; + QFontEngine *fontEngine = nullptr; }; struct QScriptItem diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp index 33adac40b2..024f0f084e 100644 --- a/src/gui/util/qgridlayoutengine.cpp +++ b/src/gui/util/qgridlayoutengine.cpp @@ -1147,7 +1147,7 @@ QLayoutPolicy::ControlTypes QGridLayoutEngine::controlTypes(LayoutSide side) con Qt::Orientation orientation = (side == Top || side == Bottom) ? Qt::Vertical : Qt::Horizontal; int row = (side == Top || side == Left) ? effectiveFirstRow(orientation) : effectiveLastRow(orientation); - QLayoutPolicy::ControlTypes result = 0; + QLayoutPolicy::ControlTypes result; for (int column = columnCount(orientation) - 1; column >= 0; --column) { if (QGridLayoutItem *item = itemAt(row, column, orientation)) diff --git a/src/gui/util/qgridlayoutengine_p.h b/src/gui/util/qgridlayoutengine_p.h index 5f0e84edb1..181326103b 100644 --- a/src/gui/util/qgridlayoutengine_p.h +++ b/src/gui/util/qgridlayoutengine_p.h @@ -276,7 +276,7 @@ class Q_GUI_EXPORT QGridLayoutItem { public: QGridLayoutItem(int row, int column, int rowSpan = 1, int columnSpan = 1, - Qt::Alignment alignment = nullptr); + Qt::Alignment alignment = { }); virtual ~QGridLayoutItem() {} inline int firstRow() const { return q_firstRows[Ver]; } @@ -339,7 +339,7 @@ private: class Q_GUI_EXPORT QGridLayoutEngine { public: - QGridLayoutEngine(Qt::Alignment defaultAlignment = Qt::Alignment(nullptr), bool snapToPixelGrid = false); + QGridLayoutEngine(Qt::Alignment defaultAlignment = { }, bool snapToPixelGrid = false); inline ~QGridLayoutEngine() { qDeleteAll(q_items); } int rowCount(Qt::Orientation orientation) const; diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp index 9d044bfd58..1b5d3370f0 100644 --- a/src/gui/vulkan/qplatformvulkaninstance.cpp +++ b/src/gui/vulkan/qplatformvulkaninstance.cpp @@ -80,6 +80,11 @@ QPlatformVulkanInstance::~QPlatformVulkanInstance() { } +void QPlatformVulkanInstance::presentAboutToBeQueued(QWindow *window) +{ + Q_UNUSED(window); +} + void QPlatformVulkanInstance::presentQueued(QWindow *window) { Q_UNUSED(window); diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h index d47c59b5db..f96f1720fb 100644 --- a/src/gui/vulkan/qplatformvulkaninstance.h +++ b/src/gui/vulkan/qplatformvulkaninstance.h @@ -77,6 +77,7 @@ public: virtual QByteArrayList enabledExtensions() const = 0; virtual PFN_vkVoidFunction getInstanceProcAddr(const char *name) = 0; virtual bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) = 0; + virtual void presentAboutToBeQueued(QWindow *window); virtual void presentQueued(QWindow *window); virtual void setDebugFilters(const QVector<QVulkanInstance::DebugFilter> &filters); diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp index 0605d88cca..764cb917ad 100644 --- a/src/gui/vulkan/qvulkaninstance.cpp +++ b/src/gui/vulkan/qvulkaninstance.cpp @@ -251,7 +251,6 @@ public: QVulkanInstancePrivate(QVulkanInstance *q) : q_ptr(q), vkInst(VK_NULL_HANDLE), - flags(0), errorCode(VK_SUCCESS) { } ~QVulkanInstancePrivate() { reset(); } @@ -775,6 +774,20 @@ bool QVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, uint32_t } /*! + This function should be called by the application's renderer before queuing + a present operation for \a window. + + While on some platforms this will be a no-op, some may perform windowing + system dependent synchronization. For example, on Wayland this will + add send a wl_surface.frame request in order to prevent the driver from + blocking for minimized windows. + */ +void QVulkanInstance::presentAboutToBeQueued(QWindow *window) +{ + d_ptr->platformInst->presentAboutToBeQueued(window); +} + +/*! This function should be called by the application's renderer after queuing a present operation for \a window. diff --git a/src/gui/vulkan/qvulkaninstance.h b/src/gui/vulkan/qvulkaninstance.h index 70f2fd5102..5b3db9a4c8 100644 --- a/src/gui/vulkan/qvulkaninstance.h +++ b/src/gui/vulkan/qvulkaninstance.h @@ -186,6 +186,7 @@ public: bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window); + void presentAboutToBeQueued(QWindow *window); void presentQueued(QWindow *window); typedef bool (*DebugFilter)(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp index 4b5c2b56ee..790bef9e14 100644 --- a/src/gui/vulkan/qvulkanwindow.cpp +++ b/src/gui/vulkan/qvulkanwindow.cpp @@ -647,18 +647,40 @@ void QVulkanWindowPrivate::init() #endif qCDebug(lcGuiVk, "Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx); - VkDeviceQueueCreateInfo queueInfo[2]; + QVector<VkDeviceQueueCreateInfo> queueInfo; + queueInfo.reserve(2); const float prio[] = { 0 }; - memset(queueInfo, 0, sizeof(queueInfo)); - queueInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueInfo[0].queueFamilyIndex = gfxQueueFamilyIdx; - queueInfo[0].queueCount = 1; - queueInfo[0].pQueuePriorities = prio; + VkDeviceQueueCreateInfo addQueueInfo; + memset(&addQueueInfo, 0, sizeof(addQueueInfo)); + addQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + addQueueInfo.queueFamilyIndex = gfxQueueFamilyIdx; + addQueueInfo.queueCount = 1; + addQueueInfo.pQueuePriorities = prio; + queueInfo.append(addQueueInfo); if (gfxQueueFamilyIdx != presQueueFamilyIdx) { - queueInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueInfo[1].queueFamilyIndex = presQueueFamilyIdx; - queueInfo[1].queueCount = 1; - queueInfo[1].pQueuePriorities = prio; + addQueueInfo.queueFamilyIndex = presQueueFamilyIdx; + addQueueInfo.queueCount = 1; + addQueueInfo.pQueuePriorities = prio; + queueInfo.append(addQueueInfo); + } + if (queueCreateInfoModifier) { + queueCreateInfoModifier(queueFamilyProps.constData(), queueCount, queueInfo); + bool foundGfxQueue = false; + bool foundPresQueue = false; + for (const VkDeviceQueueCreateInfo& createInfo : qAsConst(queueInfo)) { + foundGfxQueue |= createInfo.queueFamilyIndex == gfxQueueFamilyIdx; + foundPresQueue |= createInfo.queueFamilyIndex == presQueueFamilyIdx; + } + if (!foundGfxQueue) { + qWarning("QVulkanWindow: Graphics queue missing after call to queueCreateInfoModifier"); + status = StatusFail; + return; + } + if (!foundPresQueue) { + qWarning("QVulkanWindow: Present queue missing after call to queueCreateInfoModifier"); + status = StatusFail; + return; + } } // Filter out unsupported extensions in order to keep symmetry @@ -676,8 +698,8 @@ void QVulkanWindowPrivate::init() VkDeviceCreateInfo devInfo; memset(&devInfo, 0, sizeof(devInfo)); devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - devInfo.queueCreateInfoCount = gfxQueueFamilyIdx == presQueueFamilyIdx ? 1 : 2; - devInfo.pQueueCreateInfos = queueInfo; + devInfo.queueCreateInfoCount = queueInfo.size(); + devInfo.pQueueCreateInfos = queueInfo.constData(); devInfo.enabledExtensionCount = devExts.count(); devInfo.ppEnabledExtensionNames = devExts.constData(); @@ -1546,6 +1568,52 @@ bool QVulkanWindow::event(QEvent *e) } /*! + \typedef QVulkanWindow::QueueCreateInfoModifier + + A function function that is called during graphics initialization to add + additAional queues that should be created. + + Set if the renderer needs additional queues besides the default graphics + queue (e.g. a transfer queue). + The provided queue family properties can be used to select the indices for + the additional queues. + The renderer can subsequently request the actual queue in initResources(). + + Note when requesting additional graphics queues: Qt itself always requests + a graphics queue, you'll need to search queueCreateInfo for the appropriate + entry and manipulate it to obtain the additional queue. + + \sa setQueueCreateInfoModifier() + */ + +/*! + Return a previously set queue create info modification function. + + \sa setQueueCreateInfoModifier() + + \since 5.15 + */ +QVulkanWindow::QueueCreateInfoModifier QVulkanWindow::queueCreateInfoModifier() const +{ + Q_D(const QVulkanWindow); + return d->queueCreateInfoModifier; +} + +/*! + Set a queue create info modification function. + + \sa queueCreateInfoModifier() + + \since 5.15 + */ +void QVulkanWindow::setQueueCreateInfoModifier(QueueCreateInfoModifier modifier) +{ + Q_D(QVulkanWindow); + d->queueCreateInfoModifier = modifier; +} + + +/*! Returns true if this window has successfully initialized all Vulkan resources, including the swapchain. @@ -1950,6 +2018,10 @@ void QVulkanWindowPrivate::endFrame() presInfo.waitSemaphoreCount = 1; presInfo.pWaitSemaphores = gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem; + // Do platform-specific WM notification. F.ex. essential on Wayland in + // order to circumvent driver frame callbacks + inst->presentAboutToBeQueued(q); + err = vkQueuePresentKHR(gfxQueue, &presInfo); if (err != VK_SUCCESS) { if (err == VK_ERROR_OUT_OF_DATE_KHR) { @@ -2211,6 +2283,23 @@ VkQueue QVulkanWindow::graphicsQueue() const } /*! + Returns the family index of the active graphics queue. + + \note Calling this function is only valid from the invocation of + QVulkanWindowRenderer::initResources() up until + QVulkanWindowRenderer::releaseResources(). Implementations of + QVulkanWindowRenderer::updateQueueCreateInfo() can also call this + function. + + \since 5.15 + */ +uint32_t QVulkanWindow::graphicsQueueFamilyIndex() const +{ + Q_D(const QVulkanWindow); + return d->gfxQueueFamilyIdx; +} + +/*! Returns the active graphics command pool. \note Calling this function is only valid from the invocation of diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h index 927c81042f..530b6c0744 100644 --- a/src/gui/vulkan/qvulkanwindow.h +++ b/src/gui/vulkan/qvulkanwindow.h @@ -103,6 +103,12 @@ public: QVector<int> supportedSampleCounts(); void setSampleCount(int sampleCount); + typedef std::function<void(const VkQueueFamilyProperties *, + uint32_t, + QVector<VkDeviceQueueCreateInfo> &)> QueueCreateInfoModifier; + QueueCreateInfoModifier queueCreateInfoModifier() const; + void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier); + bool isValid() const; virtual QVulkanWindowRenderer *createRenderer(); @@ -112,6 +118,7 @@ public: const VkPhysicalDeviceProperties *physicalDeviceProperties() const; VkDevice device() const; VkQueue graphicsQueue() const; + uint32_t graphicsQueueFamilyIndex() const; VkCommandPool graphicsCommandPool() const; uint32_t hostVisibleMemoryIndex() const; uint32_t deviceLocalMemoryIndex() const; diff --git a/src/gui/vulkan/qvulkanwindow_p.h b/src/gui/vulkan/qvulkanwindow_p.h index fb374a5564..915e359673 100644 --- a/src/gui/vulkan/qvulkanwindow_p.h +++ b/src/gui/vulkan/qvulkanwindow_p.h @@ -97,11 +97,12 @@ public: int physDevIndex = 0; QVector<VkPhysicalDevice> physDevs; QVector<VkPhysicalDeviceProperties> physDevProps; - QVulkanWindow::Flags flags = nullptr; + QVulkanWindow::Flags flags; QByteArrayList requestedDevExtensions; QHash<VkPhysicalDevice, QVulkanInfoVector<QVulkanExtension> > supportedDevExtensions; QVector<VkFormat> requestedColorFormats; VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; + QVulkanWindow::QueueCreateInfoModifier queueCreateInfoModifier; VkDevice dev = VK_NULL_HANDLE; QVulkanDeviceFunctions *devFuncs; |