summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/configure.pri24
-rw-r--r--src/gui/image/qiconloader.cpp2
-rw-r--r--src/gui/image/qimage.cpp4
-rw-r--r--src/gui/image/qimage.h1
-rw-r--r--src/gui/image/qimage_conversions.cpp218
-rw-r--r--src/gui/image/qimagereader.cpp6
-rw-r--r--src/gui/image/qmovie.cpp2
-rw-r--r--src/gui/image/qpicture.cpp1
-rw-r--r--src/gui/image/qpnghandler.cpp4
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.h2
-rw-r--r--src/gui/kernel/qevent.cpp38
-rw-r--r--src/gui/kernel/qevent.h3
-rw-r--r--src/gui/kernel/qevent_p.h4
-rw-r--r--src/gui/kernel/qguiapplication.cpp40
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp32
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h2
-rw-r--r--src/gui/kernel/qopenglcontext.cpp11
-rw-r--r--src/gui/kernel/qplatformwindow.cpp4
-rw-r--r--src/gui/kernel/qscreen.cpp19
-rw-r--r--src/gui/kernel/qscreen.h1
-rw-r--r--src/gui/kernel/qtouchdevice.cpp10
-rw-r--r--src/gui/kernel/qwindowdefs.h2
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp16
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h2
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h6
-rw-r--r--src/gui/opengl/qopengldebug.cpp2
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp3
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache.cpp96
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache_p.h46
-rw-r--r--src/gui/opengl/qopenglshaderprogram.cpp137
-rw-r--r--src/gui/opengl/qopengltexture.cpp2
-rw-r--r--src/gui/opengl/qopengltexture.h2
-rw-r--r--src/gui/painting/XCONSORTIUM_LICENSE.txt43
-rw-r--r--src/gui/painting/qbackingstore.cpp5
-rw-r--r--src/gui/painting/qbezier.cpp32
-rw-r--r--src/gui/painting/qcolormatrix_p.h22
-rw-r--r--src/gui/painting/qcolorspace.cpp157
-rw-r--r--src/gui/painting/qcolorspace.h27
-rw-r--r--src/gui/painting/qcolorspace_p.h16
-rw-r--r--src/gui/painting/qcolortransferfunction_p.h4
-rw-r--r--src/gui/painting/qcolortransform.cpp12
-rw-r--r--src/gui/painting/qdrawhelper.cpp199
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp45
-rw-r--r--src/gui/painting/qicc.cpp10
-rw-r--r--src/gui/painting/qicc_p.h4
-rw-r--r--src/gui/painting/qpagesize.cpp8
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp59
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h2
-rw-r--r--src/gui/painting/qpainter.cpp2
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp31
-rw-r--r--src/gui/painting/qplatformbackingstore.h3
-rw-r--r--src/gui/painting/qregion.cpp54
-rw-r--r--src/gui/painting/qrgba64_p.h2
-rw-r--r--src/gui/painting/qt_attribution.json15
-rw-r--r--src/gui/rhi/cs_tdr_p.h225
-rw-r--r--src/gui/rhi/qrhi.cpp558
-rw-r--r--src/gui/rhi/qrhi_p.h200
-rw-r--r--src/gui/rhi/qrhi_p_p.h241
-rw-r--r--src/gui/rhi/qrhid3d11.cpp802
-rw-r--r--src/gui/rhi/qrhid3d11_p.h3
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h46
-rw-r--r--src/gui/rhi/qrhigles2.cpp642
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h37
-rw-r--r--src/gui/rhi/qrhimetal.mm756
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h13
-rw-r--r--src/gui/rhi/qrhinull.cpp165
-rw-r--r--src/gui/rhi/qrhinull_p_p.h11
-rw-r--r--src/gui/rhi/qrhiprofiler.cpp14
-rw-r--r--src/gui/rhi/qrhiprofiler_p_p.h6
-rw-r--r--src/gui/rhi/qrhivulkan.cpp918
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h35
-rw-r--r--src/gui/rhi/qshader.cpp8
-rw-r--r--src/gui/rhi/qshaderdescription.cpp2
-rw-r--r--src/gui/rhi/tdr.hlsl9
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qfont.cpp14
-rw-r--r--src/gui/text/qfontdatabase.cpp2
-rw-r--r--src/gui/text/qfontdatabase.h1
-rw-r--r--src/gui/text/qplatformfontdatabase.h2
-rw-r--r--src/gui/text/qtextdocument.cpp31
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp2
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp44
-rw-r--r--src/gui/text/qtextengine.cpp15
-rw-r--r--src/gui/text/qtextformat.cpp1
-rw-r--r--src/gui/text/qtextformat.h2
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp6
-rw-r--r--src/gui/text/qtextmarkdownimporter_p.h2
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp4
-rw-r--r--src/gui/text/qtextodfwriter.cpp2
-rw-r--r--src/gui/text/qtextoption.h2
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.cpp5
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.h1
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp14
-rw-r--r--src/gui/vulkan/qvulkaninstance.h1
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp129
-rw-r--r--src/gui/vulkan/qvulkanwindow.h7
-rw-r--r--src/gui/vulkan/qvulkanwindow_p.h1
98 files changed, 4095 insertions, 2382 deletions
diff --git a/src/gui/configure.pri b/src/gui/configure.pri
index 1b95449a10..490ef0df28 100644
--- a/src/gui/configure.pri
+++ b/src/gui/configure.pri
@@ -1,18 +1,22 @@
# custom tests
defineTest(qtConfLibrary_freetype) {
- TRY_INCLUDEPATHS = $$EXTRA_INCLUDEPATH $$QMAKE_INCDIR_X11
- haiku: TRY_INCLUDEPATHS += /system/develop/headers
- TRY_INCLUDEPATHS += $$QMAKE_DEFAULT_INCDIR
- for (p, TRY_INCLUDEPATHS) {
- includedir = $$p/freetype2
- exists($$includedir) {
- $${1}.includedir = $$includedir
- export($${1}.includedir)
- return(true)
+ input = $$eval($${2}.alias)
+ isEmpty(config.input.$${input}.incdir) {
+ TRY_INCLUDEPATHS = $$EXTRA_INCLUDEPATH $$QMAKE_INCDIR_X11
+ haiku: TRY_INCLUDEPATHS += /system/develop/headers
+ TRY_INCLUDEPATHS += $$QMAKE_DEFAULT_INCDIRS
+ for (p, TRY_INCLUDEPATHS) {
+ includedir = $$p/freetype2
+ exists($$includedir) {
+ config.input.$${input}.incdir = $$includedir
+ export(config.input.$${input}.incdir)
+ break()
+ }
}
}
- return(true)
+ qtConfLibrary_inline($$1, $$2): return(true)
+ return(false)
}
# Check for Direct X shader compiler 'fxc'.
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 1d0c93f26f..27c82bc09f 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -281,7 +281,7 @@ static quint32 icon_name_hash(const char *p)
QVector<const char *> QIconCacheGtkReader::lookup(const QStringRef &name)
{
QVector<const char *> ret;
- if (!isValid())
+ if (!isValid() || name.isEmpty())
return ret;
QByteArray nameUtf8 = name.toUtf8();
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index b7f67cd7ef..dda407181a 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -3370,7 +3370,7 @@ void QImage::mirrored_inplace(bool horizontal, bool vertical)
\sa {QImage#Image Transformations}{Image Transformations}
*/
-inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
+static inline void rgbSwapped_generic(int width, int height, const QImage *src, QImage *dst, const QPixelLayout* layout)
{
const RbSwapFunc func = layout->rbSwap;
if (!func) {
@@ -5025,7 +5025,7 @@ QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace) const
QColorSpace QImage::colorSpace() const
{
if (!d)
- return QColorSpace::Undefined;
+ return QColorSpace();
return d->colorSpace;
}
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index c657d6067f..73c960f13f 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -68,7 +68,6 @@ class QMatrix;
class QStringList;
class QTransform;
class QVariant;
-template <class T> class QList;
template <class T> class QVector;
struct QImageData;
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 539bac222a..9e1df7058c 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -564,6 +564,67 @@ static bool convert_RGBA_to_ARGB_inplace(QImageData *data, Qt::ImageConversionFl
return true;
}
+static void convert_rgbswap_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const RbSwapFunc func = qPixelLayouts[src->format].rbSwap;
+ Q_ASSERT(func);
+
+ const qsizetype sbpl = src->bytes_per_line;
+ const qsizetype dbpl = dest->bytes_per_line;
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ func(dest_data, src_data, src->width);
+
+ src_data += sbpl;
+ dest_data += dbpl;
+ }
+}
+
+static bool convert_rgbswap_generic_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ const RbSwapFunc func = qPixelLayouts[data->format].rbSwap;
+ Q_ASSERT(func);
+
+ const qsizetype bpl = data->bytes_per_line;
+ uchar *line_data = data->data;
+
+ for (int i = 0; i < data->height; ++i) {
+ func(line_data, line_data, data->width);
+ line_data += bpl;
+ }
+
+ switch (data->format) {
+ case QImage::Format_RGB888:
+ data->format = QImage::Format_BGR888;
+ break;
+ case QImage::Format_BGR888:
+ data->format = QImage::Format_RGB888;
+ break;
+ case QImage::Format_BGR30:
+ data->format = QImage::Format_RGB30;
+ break;
+ case QImage::Format_A2BGR30_Premultiplied:
+ data->format = QImage::Format_A2RGB30_Premultiplied;
+ break;
+ case QImage::Format_RGB30:
+ data->format = QImage::Format_BGR30;
+ break;
+ case QImage::Format_A2RGB30_Premultiplied:
+ data->format = QImage::Format_A2BGR30_Premultiplied;
+ break;
+ default:
+ Q_UNREACHABLE();
+ data->format = QImage::Format_Invalid;
+ return false;
+ }
+ return true;
+}
+
template<QtPixelOrder PixelOrder, bool RGBA>
static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
@@ -693,74 +754,10 @@ static bool convert_A2RGB30_PM_to_RGB30_inplace(QImageData *data, Qt::ImageConve
return true;
}
-static void convert_BGR30_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGB30 || src->format == QImage::Format_BGR30 ||
- src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied);
- Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30 ||
- dest->format == QImage::Format_A2RGB30_Premultiplied || dest->format == QImage::Format_A2BGR30_Premultiplied);
- 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 quint32 *src_data = (quint32 *) src->data;
- quint32 *dest_data = (quint32 *) dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- const quint32 *end = src_data + src->width;
- while (src_data < end) {
- *dest_data = qRgbSwapRgb30(*src_data);
- ++src_data;
- ++dest_data;
- }
- src_data += src_pad;
- dest_data += dest_pad;
- }
-}
-
-static bool convert_BGR30_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30 ||
- data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied);
-
- const int pad = (data->bytes_per_line >> 2) - data->width;
- uint *rgb_data = (uint *) data->data;
-
- for (int i = 0; i < data->height; ++i) {
- const uint *end = rgb_data + data->width;
- while (rgb_data < end) {
- *rgb_data = qRgbSwapRgb30(*rgb_data);
- ++rgb_data;
- }
- rgb_data += pad;
- }
-
- switch (data->format) {
- case QImage::Format_BGR30:
- data->format = QImage::Format_RGB30;
- break;
- case QImage::Format_A2BGR30_Premultiplied:
- data->format = QImage::Format_A2RGB30_Premultiplied;
- break;
- case QImage::Format_RGB30:
- data->format = QImage::Format_BGR30;
- break;
- case QImage::Format_A2RGB30_Premultiplied:
- data->format = QImage::Format_A2BGR30_Premultiplied;
- break;
- default:
- Q_UNREACHABLE();
- data->format = QImage::Format_Invalid;
- return false;
- }
- return true;
-}
-
static bool convert_BGR30_to_A2RGB30_inplace(QImageData *data, Qt::ImageConversionFlags flags)
{
Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30);
- if (!convert_BGR30_to_RGB30_inplace(data, flags))
+ if (!convert_rgbswap_generic_inplace(data, flags))
return false;
if (data->format == QImage::Format_RGB30)
@@ -1421,69 +1418,6 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt
}
}
-static void convert_RGB888_to_BGR888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
-{
- Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888);
- Q_ASSERT(dest->format == QImage::Format_RGB888 || dest->format == QImage::Format_BGR888);
- Q_ASSERT(src->width == dest->width);
- Q_ASSERT(src->height == dest->height);
-
- const qsizetype sbpl = src->bytes_per_line;
- const qsizetype dbpl = dest->bytes_per_line;
- const uchar *src_data = src->data;
- uchar *dest_data = dest->data;
-
- for (int i = 0; i < src->height; ++i) {
- int pixel = 0;
- // Handle 4 pixels (12 bytes) at a time
- for (; pixel + 3 < src->width; pixel += 4) {
- const uchar *src = src_data + pixel * 3;
- quint32 *dest_packed = (quint32 *) (dest_data + pixel * 3);
- dest_packed[0] = (src[5] << 24) | (src[0] << 16) | (src[1] << 8) | (src[2] << 0);
- dest_packed[1] = (src[7] << 24) | (src[8] << 16) | (src[3] << 8) | (src[4] << 0);
- dest_packed[2] = (src[9] << 24) | (src[10] << 16) | (src[11] << 8) | (src[6] << 0);
- }
-
- // epilog: handle left over pixels
- for (; pixel < src->width; ++pixel) {
- dest_data[pixel * 3 + 0] = src_data[pixel * 3 + 2];
- dest_data[pixel * 3 + 1] = src_data[pixel * 3 + 1];
- dest_data[pixel * 3 + 2] = src_data[pixel * 3 + 0];
- }
-
- src_data += sbpl;
- dest_data += dbpl;
- }
-}
-
-static bool convert_RGB888_to_BGR888_inplace(QImageData *data, Qt::ImageConversionFlags)
-{
- Q_ASSERT(data->format == QImage::Format_RGB888 || data->format == QImage::Format_BGR888);
-
- const qsizetype bpl = data->bytes_per_line;
- uchar *line_data = data->data;
-
- for (int i = 0; i < data->height; ++i) {
- for (int j = 0; j < data->width; ++j)
- qSwap(line_data[j * 3 + 0], line_data[j * 3 + 2]);
- line_data += bpl;
- }
-
- switch (data->format) {
- case QImage::Format_RGB888:
- data->format = QImage::Format_BGR888;
- break;
- case QImage::Format_BGR888:
- data->format = QImage::Format_RGB888;
- break;
- default:
- Q_UNREACHABLE();
- data->format = QImage::Format_Invalid;
- return false;
- }
- return true;
-}
-
static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
{
QVector<QRgb> colorTable = ctbl;
@@ -2635,7 +2569,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- convert_RGB888_to_BGR888,
+ convert_rgbswap_generic,
}, // Format_RGB888
{
@@ -2781,8 +2715,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
convert_passthrough,
- convert_BGR30_to_RGB30,
- convert_BGR30_to_RGB30,
+ convert_rgbswap_generic,
+ convert_rgbswap_generic,
0, 0,
0, 0, 0, 0, 0
}, // Format_BGR30
@@ -2809,7 +2743,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_RGB30<false>,
0,
convert_A2RGB30_PM_to_RGB30<true>,
- convert_BGR30_to_RGB30,
+ convert_rgbswap_generic,
0, 0,
0, 0, 0, 0, 0
}, // Format_A2BGR30_Premultiplied
@@ -2833,8 +2767,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- convert_BGR30_to_RGB30,
- convert_BGR30_to_RGB30,
+ convert_rgbswap_generic,
+ convert_rgbswap_generic,
0,
convert_passthrough,
0, 0, 0, 0, 0, 0, 0
@@ -2860,7 +2794,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_ARGB<PixelOrderRGB, true>,
0,
convert_A2RGB30_PM_to_RGB30<true>,
- convert_BGR30_to_RGB30,
+ convert_rgbswap_generic,
convert_A2RGB30_PM_to_RGB30<false>,
0,
0, 0,
@@ -3013,7 +2947,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- convert_RGB888_to_BGR888,
+ convert_rgbswap_generic,
0,
0,
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@@ -3161,7 +3095,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
}, // Format_ARGB8555_Premultiplied
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- convert_RGB888_to_BGR888_inplace
+ convert_rgbswap_generic_inplace
}, // Format_RGB888
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -3267,7 +3201,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0, // self
convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>,
- convert_BGR30_to_RGB30_inplace,
+ convert_rgbswap_generic_inplace,
convert_BGR30_to_A2RGB30_inplace,
0, 0,
0, 0, 0, 0, 0
@@ -3295,7 +3229,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_A2RGB30_PM_to_RGB30_inplace<false>,
0, // self
convert_A2RGB30_PM_to_RGB30_inplace<true>,
- convert_BGR30_to_RGB30_inplace,
+ convert_rgbswap_generic_inplace,
0, 0, 0, 0, 0, 0, 0
}, // Format_A2BGR30_Premultiplied
{
@@ -3318,7 +3252,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
- convert_BGR30_to_RGB30_inplace,
+ convert_rgbswap_generic_inplace,
convert_BGR30_to_A2RGB30_inplace,
0, // self
convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>,
@@ -3345,7 +3279,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_A2RGB30_PM_to_ARGB_inplace<PixelOrderRGB, true>,
0,
convert_A2RGB30_PM_to_RGB30_inplace<true>,
- convert_BGR30_to_RGB30_inplace,
+ convert_rgbswap_generic_inplace,
convert_A2RGB30_PM_to_RGB30_inplace<false>,
0, // self
0, 0,
@@ -3427,7 +3361,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
}, // Format_Grayscale16
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- convert_RGB888_to_BGR888_inplace,
+ convert_rgbswap_generic_inplace,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_BGR888
};
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 6a0763e696..dff24b449a 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -150,7 +150,7 @@
// factory loader
#include <qcoreapplication.h>
#include <private/qfactoryloader_p.h>
-#include <QMutexLocker>
+#include <QtCore/private/qlocking_p.h>
// for qt_getImageText
#include <private/qimage_p.h>
@@ -186,8 +186,8 @@ static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
QByteArray suffix;
#ifndef QT_NO_IMAGEFORMATPLUGIN
- static QMutex mutex;
- QMutexLocker locker(&mutex);
+ static QBasicMutex mutex;
+ const auto locker = qt_scoped_lock(mutex);
typedef QMultiMap<int, QString> PluginKeyMap;
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp
index 3e975115ab..25fce050a1 100644
--- a/src/gui/image/qmovie.cpp
+++ b/src/gui/image/qmovie.cpp
@@ -414,7 +414,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
} else {
// We've read all frames now. Return an end marker
haveReadAll = true;
- return QFrameInfo::endMarker();
+ return frameNumber == greatestFrameNumber + 1 ? QFrameInfo::endMarker() : QFrameInfo();
}
}
}
diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp
index 84de91353a..e119103462 100644
--- a/src/gui/image/qpicture.cpp
+++ b/src/gui/image/qpicture.cpp
@@ -57,6 +57,7 @@
#include "qregexp.h"
#include "qregion.h"
#include "qdebug.h"
+#include <QtCore/private/qlocking_p.h>
#include <algorithm>
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/itemmodels/qstandarditemmodel.h b/src/gui/itemmodels/qstandarditemmodel.h
index 435b66591c..f1c6e6df5c 100644
--- a/src/gui/itemmodels/qstandarditemmodel.h
+++ b/src/gui/itemmodels/qstandarditemmodel.h
@@ -53,8 +53,6 @@ QT_REQUIRE_CONFIG(standarditemmodel);
QT_BEGIN_NAMESPACE
-template <class T> class QList;
-
class QStandardItemModel;
class QStandardItemPrivate;
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 8e5945be41..f2f083c277 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -791,37 +791,44 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta
\obsolete
This constructor has been deprecated.
*/
-
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
: QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation,
buttons, modifiers, Qt::NoScrollPhase)
{}
+QT_WARNING_POP
/*!
\obsolete
This constructor has been deprecated.
*/
-
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase)
: QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation,
buttons, modifiers, phase, Qt::MouseEventNotSynthesized)
{}
+QT_WARNING_POP
/*!
\obsolete
This constructor has been deprecated.
*/
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, Qt::MouseEventSource source)
: QWheelEvent(pos, globalPos, pixelDelta, angleDelta, qt4Delta, qt4Orientation,
buttons, modifiers, phase, source, false)
{}
+QT_WARNING_POP
/*!
\obsolete
@@ -931,6 +938,30 @@ QWheelEvent::~QWheelEvent()
\endlist
*/
+/*!
+ \fn QPoint QWheelEvent::position() const
+
+ Returns the position of the mouse cursor relative to the widget
+ that received the event.
+
+ If you move your widgets around in response to mouse events,
+ use globalPosition() instead of this function.
+
+ \sa globalPosition()
+*/
+
+/*!
+ \fn QPoint QWheelEvent::globalPosition() const
+
+ Returns the global position of the mouse pointer \e{at the time
+ of the event}. This is important on asynchronous window systems
+ such as X11; whenever you move your widgets around in response to
+ mouse events, globalPosition() can differ a lot from the current
+ cursor position returned by QCursor::pos().
+
+ \sa position()
+*/
+
#if QT_DEPRECATED_SINCE(5, 15)
/*!
\fn int QWheelEvent::delta() const
@@ -3895,12 +3926,15 @@ QDebug operator<<(QDebug dbg, const QEvent *e)
case QEvent::Wheel: {
const QWheelEvent *we = static_cast<const QWheelEvent *>(e);
dbg << "QWheelEvent(" << we->phase();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED // delta() and orientation()
if (!we->pixelDelta().isNull() || !we->angleDelta().isNull())
dbg << ", pixelDelta=" << we->pixelDelta() << ", angleDelta=" << we->angleDelta();
#if QT_DEPRECATED_SINCE(5, 14)
else if (int qt4Delta = we->delta())
dbg << ", delta=" << qt4Delta << ", orientation=" << we->orientation();
#endif
+QT_WARNING_POP
dbg << ')';
}
break;
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 10ef01fa1d..8a0e42f592 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -854,7 +854,6 @@ private:
qint64 m_numericId;
};
Q_DECLARE_TYPEINFO(QPointingDeviceUniqueId, Q_MOVABLE_TYPE);
-template <> class QList<QPointingDeviceUniqueId> {}; // to prevent instantiation: use QVector instead
Q_GUI_EXPORT bool operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept;
inline bool operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs) noexcept
@@ -960,6 +959,8 @@ public:
friend class QGuiApplicationPrivate;
friend class QApplication;
friend class QApplicationPrivate;
+ friend class QQuickPointerTouchEvent;
+ friend class QQuickMultiPointTouchArea;
};
#if QT_DEPRECATED_SINCE(5, 0)
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index c2d8bd72b9..b7645496f8 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -67,7 +67,8 @@ public:
state(Qt::TouchPointReleased),
pressure(-1),
rotation(0),
- ellipseDiameters(0, 0)
+ ellipseDiameters(0, 0),
+ stationaryWithModifiedProperty(false)
{ }
inline QTouchEventTouchPointPrivate *detach()
@@ -91,6 +92,7 @@ public:
QSizeF ellipseDiameters;
QVector2D velocity;
QTouchEvent::TouchPoint::InfoFlags flags;
+ bool stationaryWithModifiedProperty : 1;
QVector<QPointF> rawScreenPositions;
};
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 432618968f..fa4c419ef0 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -58,6 +58,7 @@
#include <QtCore/private/qabstracteventdispatcher_p.h>
#include <QtCore/qmutex.h>
#include <QtCore/private/qthread_p.h>
+#include <QtCore/private/qlocking_p.h>
#include <QtCore/qdir.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qnumeric.h>
@@ -1039,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
*/
@@ -2248,8 +2251,11 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
}
#if QT_DEPRECATED_SINCE(5, 14)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation,
mouse_buttons, e->modifiers, e->phase, e->source, e->inverted);
+QT_WARNING_POP
#else
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta,
mouse_buttons, e->modifiers, e->phase, e->inverted, e->source);
@@ -2527,9 +2533,8 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl
QCloseEvent event;
QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
- if (e->accepted) {
- *(e->accepted) = event.isAccepted();
- }
+
+ e->eventAccepted = event.isAccepted();
}
void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e)
@@ -2766,7 +2771,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QWindow *window = e->window.data();
typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
- bool stationaryTouchPointChangedVelocity = false;
+ bool stationaryTouchPointChangedProperty = false;
for (int i = 0; i < e->points.count(); ++i) {
QTouchEvent::TouchPoint touchPoint = e->points.at(i);
@@ -2846,7 +2851,13 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
if (touchPoint.state() == Qt::TouchPointStationary) {
if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) {
touchInfo.touchPoint.setVelocity(touchPoint.velocity());
- stationaryTouchPointChangedVelocity = true;
+ touchPoint.d->stationaryWithModifiedProperty = true;
+ stationaryTouchPointChangedProperty = true;
+ }
+ if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) {
+ touchInfo.touchPoint.setPressure(touchPoint.pressure());
+ touchPoint.d->stationaryWithModifiedProperty = true;
+ stationaryTouchPointChangedProperty = true;
}
} else {
touchInfo.touchPoint = touchPoint;
@@ -2887,7 +2898,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
break;
case Qt::TouchPointStationary:
// don't send the event if nothing changed
- if (!stationaryTouchPointChangedVelocity)
+ if (!stationaryTouchPointChangedProperty)
continue;
Q_FALLTHROUGH();
default:
@@ -3305,7 +3316,7 @@ void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
QFont QGuiApplication::font()
{
Q_ASSERT_X(QGuiApplicationPrivate::self, "QGuiApplication::font()", "no QGuiApplication instance");
- QMutexLocker locker(&applicationFontMutex);
+ const auto locker = qt_scoped_lock(applicationFontMutex);
initFontUnlocked();
return *QGuiApplicationPrivate::app_font;
}
@@ -3317,7 +3328,7 @@ QFont QGuiApplication::font()
*/
void QGuiApplication::setFont(const QFont &font)
{
- QMutexLocker locker(&applicationFontMutex);
+ auto locker = qt_unique_lock(applicationFontMutex);
const bool emitChange = !QGuiApplicationPrivate::app_font
|| (*QGuiApplicationPrivate::app_font != font);
if (!QGuiApplicationPrivate::app_font)
@@ -3326,8 +3337,11 @@ void QGuiApplication::setFont(const QFont &font)
*QGuiApplicationPrivate::app_font = font;
applicationResourceFlags |= ApplicationFontExplicitlySet;
- if (emitChange && qGuiApp)
- emit qGuiApp->fontChanged(*QGuiApplicationPrivate::app_font);
+ if (emitChange && qGuiApp) {
+ auto font = *QGuiApplicationPrivate::app_font;
+ locker.unlock();
+ emit qGuiApp->fontChanged(font);
+ }
}
/*!
@@ -3502,7 +3516,7 @@ Qt::ApplicationState QGuiApplication::applicationState()
\since 5.14
Sets the high-DPI scale factor rounding policy for the application. The
- policy decides how non-integer scale factors (such as Windows 150%) are
+ \a policy decides how non-integer scale factors (such as Windows 150%) are
handled, for applications that have AA_EnableHighDpiScaling enabled.
The two principal options are whether fractional scale factors should
@@ -4078,7 +4092,7 @@ void QGuiApplicationPrivate::notifyThemeChanged()
sendApplicationPaletteChange();
}
if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
- QMutexLocker locker(&applicationFontMutex);
+ const auto locker = qt_scoped_lock(applicationFontMutex);
clearFontUnlocked();
initFontUnlocked();
}
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index c031885d5d..76548d5d86 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -86,7 +86,7 @@ static inline qreal initialGlobalScaleFactor()
qreal result = 1;
if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) {
bool ok;
- const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok);
+ const qreal f = qEnvironmentVariable(scaleFactorEnvVar).toDouble(&ok);
if (ok && f > 0) {
qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f;
result = f;
@@ -284,7 +284,8 @@ static inline bool usePixelDensity()
return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling)
|| (screenEnvValueOk && screenEnvValue > 0)
|| (enableEnvValueOk && enableEnvValue > 0)
- || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto");
+ || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)
+ && qEnvironmentVariable(legacyDevicePixelEnvVar).compare(QLatin1String("auto"), Qt::CaseInsensitive) == 0);
}
qreal QHighDpiScaling::rawScaleFactor(const QPlatformScreen *screen)
@@ -506,20 +507,20 @@ void QHighDpiScaling::updateHighDpiScaling()
}
if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) {
int i = 0;
- const auto specs = qgetenv(screenFactorsEnvVar).split(';');
- for (const QByteArray &spec : specs) {
- int equalsPos = spec.lastIndexOf('=');
+ const QString spec = qEnvironmentVariable(screenFactorsEnvVar);
+ const auto specs = spec.splitRef(QLatin1Char(';'));
+ for (const QStringRef &spec : specs) {
+ int equalsPos = spec.lastIndexOf(QLatin1Char('='));
qreal factor = 0;
if (equalsPos > 0) {
// support "name=factor"
- QByteArray name = spec.mid(0, equalsPos);
- QByteArray f = spec.mid(equalsPos + 1);
bool ok;
- factor = f.toDouble(&ok);
+ const auto name = spec.left(equalsPos);
+ factor = spec.mid(equalsPos + 1).toDouble(&ok);
if (ok && factor > 0 ) {
const auto screens = QGuiApplication::screens();
for (QScreen *s : screens) {
- if (s->name() == QString::fromLocal8Bit(name)) {
+ if (s->name() == name) {
setScreenFactor(s, factor);
break;
}
@@ -537,7 +538,7 @@ void QHighDpiScaling::updateHighDpiScaling()
++i;
}
}
- m_active = m_globalScalingActive || m_usePixelDensity;
+ m_active = m_globalScalingActive || m_screenFactorSet || m_usePixelDensity;
}
/*
@@ -679,8 +680,11 @@ QDpi QHighDpiScaling::logicalDpi(const QScreen *screen)
if (!screen || !screen->handle())
return QDpi(96, 96);
- if (!m_usePixelDensity)
- return QPlatformScreen::overrideDpi(screen->handle()->logicalDpi());
+ if (!m_usePixelDensity) {
+ const qreal screenScaleFactor = screenSubfactor(screen->handle());
+ const QDpi dpi = QPlatformScreen::overrideDpi(screen->handle()->logicalDpi());
+ return QDpi{ dpi.first / screenScaleFactor, dpi.second / screenScaleFactor };
+ }
const qreal scaleFactor = rawScaleFactor(screen->handle());
const qreal roundedScaleFactor = roundScaleFactor(scaleFactor);
@@ -711,8 +715,10 @@ QHighDpiScaling::ScaleAndOrigin QHighDpiScaling::scaleAndOrigin(const QWindow *w
{
if (!m_active)
return { qreal(1), QPoint() };
+
QScreen *screen = window ? window->screen() : QGuiApplication::primaryScreen();
- return scaleAndOrigin(screen, nativePosition);
+ const bool searchScreen = !window || window->isTopLevel();
+ return scaleAndOrigin(screen, searchScreen ? nativePosition : nullptr);
}
#endif //QT_NO_HIGHDPISCALING
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/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 6f51fe3095..638eb1d12f 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -45,6 +45,7 @@
#include <QtCore/QThreadStorage>
#include <QtCore/QThread>
+#include <QtCore/private/qlocking_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qopengl_p.h>
@@ -1442,7 +1443,7 @@ QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup()
void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx)
{
- QMutexLocker locker(&m_mutex);
+ const auto locker = qt_scoped_lock(m_mutex);
m_refs.ref();
m_shares << ctx;
}
@@ -1454,7 +1455,7 @@ void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx)
bool deleteObject = false;
{
- QMutexLocker locker(&m_mutex);
+ const auto locker = qt_scoped_lock(m_mutex);
m_shares.removeOne(ctx);
if (ctx == m_context && !m_shares.isEmpty())
@@ -1502,7 +1503,7 @@ void QOpenGLContextGroupPrivate::cleanup()
void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
{
- QMutexLocker locker(&m_mutex);
+ const auto locker = qt_scoped_lock(m_mutex);
const QList<QOpenGLSharedResource *> pending = m_pendingDeletion;
m_pendingDeletion.clear();
@@ -1543,7 +1544,7 @@ void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group)
: m_group(group)
{
- QMutexLocker locker(&m_group->d_func()->m_mutex);
+ const auto locker = qt_scoped_lock(m_group->d_func()->m_mutex);
m_group->d_func()->m_sharedResources << this;
}
@@ -1559,7 +1560,7 @@ void QOpenGLSharedResource::free()
return;
}
- QMutexLocker locker(&m_group->d_func()->m_mutex);
+ const auto locker = qt_scoped_lock(m_group->d_func()->m_mutex);
m_group->d_func()->m_sharedResources.removeOne(this);
m_group->d_func()->m_pendingDeletion << this;
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 4e95751397..2a0cb1094c 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -348,9 +348,7 @@ void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); }
*/
bool QPlatformWindow::close()
{
- bool accepted = false;
- QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window(), &accepted);
- return accepted;
+ return QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window());
}
/*!
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/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp
index ea187f54aa..8293fddc59 100644
--- a/src/gui/kernel/qtouchdevice.cpp
+++ b/src/gui/kernel/qtouchdevice.cpp
@@ -228,7 +228,7 @@ TouchDevices::TouchDevices()
*/
QList<const QTouchDevice *> QTouchDevice::devices()
{
- QMutexLocker lock(&devicesMutex);
+ const auto locker = qt_scoped_lock(devicesMutex);
return deviceList->list;
}
@@ -237,13 +237,13 @@ QList<const QTouchDevice *> QTouchDevice::devices()
*/
bool QTouchDevicePrivate::isRegistered(const QTouchDevice *dev)
{
- QMutexLocker locker(&devicesMutex);
+ const auto locker = qt_scoped_lock(devicesMutex);
return deviceList->list.contains(dev);
}
const QTouchDevice *QTouchDevicePrivate::deviceById(quint8 id)
{
- QMutexLocker locker(&devicesMutex);
+ const auto locker = qt_scoped_lock(devicesMutex);
for (const QTouchDevice *dev : qAsConst(deviceList->list))
if (QTouchDevicePrivate::get(const_cast<QTouchDevice *>(dev))->id == id)
return dev;
@@ -255,7 +255,7 @@ const QTouchDevice *QTouchDevicePrivate::deviceById(quint8 id)
*/
void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev)
{
- QMutexLocker lock(&devicesMutex);
+ const auto locker = qt_scoped_lock(devicesMutex);
deviceList->list.append(dev);
}
@@ -264,7 +264,7 @@ void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev)
*/
void QTouchDevicePrivate::unregisterDevice(const QTouchDevice *dev)
{
- QMutexLocker lock(&devicesMutex);
+ const auto locker = qt_scoped_lock(devicesMutex);
deviceList->list.removeOne(dev);
}
diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h
index b4f3ed4712..cb0842da8c 100644
--- a/src/gui/kernel/qwindowdefs.h
+++ b/src/gui/kernel/qwindowdefs.h
@@ -43,6 +43,7 @@
#include <QtGui/qtguiglobal.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qcontainerfwd.h>
QT_BEGIN_NAMESPACE
@@ -80,7 +81,6 @@ class QString;
class QByteArray;
class QApplication;
-template<typename T> class QList;
typedef QList<QWidget *> QWidgetList;
typedef QList<QWindow *> QWindowList;
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 40a298226a..5f61853a6d 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -340,13 +340,11 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QReg
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleCloseEvent, QWindow *window, bool *accepted)
+QT_DEFINE_QPA_EVENT_HANDLER(bool, handleCloseEvent, QWindow *window)
{
- if (window) {
- QWindowSystemInterfacePrivate::CloseEvent *e =
- new QWindowSystemInterfacePrivate::CloseEvent(window, accepted);
- QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
- }
+ Q_ASSERT(window);
+ auto *event = new QWindowSystemInterfacePrivate::CloseEvent(window);
+ return QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(event);
}
/*!
@@ -619,6 +617,7 @@ bool QWindowSystemInterface::isTouchDeviceRegistered(const QTouchDevice *device)
static int g_nextPointId = 1;
// map from device-independent point id (arbitrary) to "Qt point" ids
+QMutex QWindowSystemInterfacePrivate::pointIdMapMutex;
typedef QMap<quint64, int> PointIdMap;
Q_GLOBAL_STATIC(PointIdMap, g_pointIdMap)
@@ -636,6 +635,8 @@ Q_GLOBAL_STATIC(PointIdMap, g_pointIdMap)
*/
static int acquireCombinedPointId(quint8 deviceId, int pointId)
{
+ QMutexLocker locker(&QWindowSystemInterfacePrivate::pointIdMapMutex);
+
quint64 combinedId64 = (quint64(deviceId) << 32) + pointId;
auto it = g_pointIdMap->constFind(combinedId64);
int uid;
@@ -695,6 +696,8 @@ QList<QTouchEvent::TouchPoint>
}
if (states == Qt::TouchPointReleased) {
+ QMutexLocker locker(&QWindowSystemInterfacePrivate::pointIdMapMutex);
+
// All points on deviceId have been released.
// Remove all points associated with that device from g_pointIdMap.
// (On other devices, some touchpoints might still be pressed.
@@ -714,6 +717,7 @@ QList<QTouchEvent::TouchPoint>
void QWindowSystemInterfacePrivate::clearPointIdMap()
{
+ QMutexLocker locker(&QWindowSystemInterfacePrivate::pointIdMapMutex);
g_pointIdMap->clear();
g_nextPointId = 1;
}
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index fd70eda9ff..4a0bc858a9 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -194,7 +194,7 @@ public:
static void handleExposeEvent(QWindow *window, const QRegion &region);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleCloseEvent(QWindow *window, bool *accepted = nullptr);
+ static bool handleCloseEvent(QWindow *window);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleEnterEvent(QWindow *window, const QPointF &local = QPointF(), const QPointF& global = QPointF());
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index d6513f1836..55fd181ef0 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -123,11 +123,10 @@ public:
class CloseEvent : public WindowSystemEvent {
public:
- explicit CloseEvent(QWindow *w, bool *a = nullptr)
- : WindowSystemEvent(Close), window(w), accepted(a)
+ explicit CloseEvent(QWindow *w)
+ : WindowSystemEvent(Close), window(w)
{ }
QPointer<QWindow> window;
- bool *accepted;
};
class GeometryChangeEvent : public WindowSystemEvent {
@@ -529,6 +528,7 @@ public:
static QWaitCondition eventsFlushed;
static QMutex flushEventMutex;
+ static QMutex pointIdMapMutex;
static QAtomicInt eventAccepted;
static QList<QTouchEvent::TouchPoint>
diff --git a/src/gui/opengl/qopengldebug.cpp b/src/gui/opengl/qopengldebug.cpp
index 9f1bb76869..462a4fdb3b 100644
--- a/src/gui/opengl/qopengldebug.cpp
+++ b/src/gui/opengl/qopengldebug.cpp
@@ -1807,7 +1807,7 @@ QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const
\note Message texts are encoded in UTF-8 when they get passed to OpenGL, so
their size in bytes does not usually match the amount of UTF-16 code units,
- as returned f.i. by QString::length(). (It does if the message contains
+ as returned, for instance, by QString::length(). (It does if the message contains
7-bit ASCII only data, which is typical for debug messages.)
*/
qint64 QOpenGLDebugLogger::maximumMessageLength() const
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index c087326068..47394999c6 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -1474,6 +1474,8 @@ void QOpenGL2PaintEngineEx::renderHintsChanged()
#ifndef QT_OPENGL_ES_2
if (!QOpenGLContext::currentContext()->isOpenGLES()) {
Q_D(QOpenGL2PaintEngineEx);
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
if ((state()->renderHints & QPainter::Antialiasing)
#if QT_DEPRECATED_SINCE(5, 14)
|| (state()->renderHints & QPainter::HighQualityAntialiasing)
@@ -1482,6 +1484,7 @@ void QOpenGL2PaintEngineEx::renderHintsChanged()
d->funcs.glEnable(GL_MULTISAMPLE);
else
d->funcs.glDisable(GL_MULTISAMPLE);
+QT_WARNING_POP
}
#endif // QT_OPENGL_ES_2
diff --git a/src/gui/opengl/qopenglprogrambinarycache.cpp b/src/gui/opengl/qopenglprogrambinarycache.cpp
index 8d4d8ed183..72bdacf43f 100644
--- a/src/gui/opengl/qopenglprogrambinarycache.cpp
+++ b/src/gui/opengl/qopenglprogrambinarycache.cpp
@@ -44,7 +44,9 @@
#include <QStandardPaths>
#include <QDir>
#include <QSaveFile>
+#include <QCoreApplication>
#include <QLoggingCategory>
+#include <QCryptographicHash>
#ifdef Q_OS_UNIX
#include <sys/mman.h>
@@ -53,7 +55,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
+Q_LOGGING_CATEGORY(lcOpenGLProgramDiskCache, "qt.opengl.diskcache")
#ifndef GL_CONTEXT_LOST
#define GL_CONTEXT_LOST 0x0507
@@ -63,6 +65,10 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_SHADER_CACHE)
#define GL_PROGRAM_BINARY_LENGTH 0x8741
#endif
+#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#endif
+
const quint32 BINSHADER_MAGIC = 0x5174;
const quint32 BINSHADER_VERSION = 0x3;
const quint32 BINSHADER_QTVERSION = QT_VERSION;
@@ -94,6 +100,15 @@ GLEnvInfo::GLEnvInfo()
glversion = QByteArray(version);
}
+QByteArray QOpenGLProgramBinaryCache::ProgramDesc::cacheKey() const
+{
+ QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
+ for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : shaders)
+ keyBuilder.addData(shader.source);
+
+ return keyBuilder.result().toHex();
+}
+
static inline bool qt_ensureWritableDir(const QString &name)
{
QDir::root().mkpath(name);
@@ -113,7 +128,7 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
}
- qCDebug(DBG_SHADER_CACHE, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
+ qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
@@ -144,24 +159,24 @@ static inline QByteArray readStr(const uchar **p)
bool QOpenGLProgramBinaryCache::verifyHeader(const QByteArray &buf) const
{
if (buf.size() < BASE_HEADER_SIZE) {
- qCDebug(DBG_SHADER_CACHE, "Cached size too small");
+ qCDebug(lcOpenGLProgramDiskCache, "Cached size too small");
return false;
}
const uchar *p = reinterpret_cast<const uchar *>(buf.constData());
if (readUInt(&p) != BINSHADER_MAGIC) {
- qCDebug(DBG_SHADER_CACHE, "Magic does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Magic does not match");
return false;
}
if (readUInt(&p) != BINSHADER_VERSION) {
- qCDebug(DBG_SHADER_CACHE, "Version does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Version does not match");
return false;
}
if (readUInt(&p) != BINSHADER_QTVERSION) {
- qCDebug(DBG_SHADER_CACHE, "Qt version does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Qt version does not match");
return false;
}
if (readUInt(&p) != sizeof(quintptr)) {
- qCDebug(DBG_SHADER_CACHE, "Architecture does not match");
+ qCDebug(lcOpenGLProgramDiskCache, "Architecture does not match");
return false;
}
return true;
@@ -186,7 +201,7 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLenum err = funcs->glGetError();
if (err != GL_NO_ERROR) {
- qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return false;
@@ -194,13 +209,13 @@ bool QOpenGLProgramBinaryCache::setProgramBinary(uint programId, uint blobFormat
GLint linkStatus = 0;
funcs->glGetProgramiv(programId, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE) {
- qCDebug(DBG_SHADER_CACHE, "Program binary failed to load for program %u, size %d, "
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary failed to load for program %u, size %d, "
"format 0x%x, linkStatus = 0x%x, err = 0x%x",
programId, blobSize, blobFormat, linkStatus, err);
return false;
}
- qCDebug(DBG_SHADER_CACHE, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary set for program %u, size %d, format 0x%x, err = 0x%x",
programId, blobSize, blobFormat, err);
return true;
}
@@ -263,10 +278,9 @@ public:
bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
{
- if (m_memCache.contains(cacheKey)) {
- const MemCacheEntry *e = m_memCache[cacheKey];
+ QMutexLocker lock(&m_mutex);
+ if (const MemCacheEntry *e = m_memCache.object(cacheKey))
return setProgramBinary(programId, e->format, e->blob.constData(), e->blob.size());
- }
QByteArray buf;
const QString fn = cacheFileName(cacheKey);
@@ -309,19 +323,19 @@ bool QOpenGLProgramBinaryCache::load(const QByteArray &cacheKey, uint programId)
if (vendor != info.glvendor) {
// readStr returns non-null terminated strings just pointing to inside
// 'p' so must print these via the stream qCDebug and not constData().
- qCDebug(DBG_SHADER_CACHE) << "GL_VENDOR does not match" << vendor << info.glvendor;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_VENDOR does not match" << vendor << info.glvendor;
undertaker.setActive();
return false;
}
QByteArray renderer = readStr(&p);
if (renderer != info.glrenderer) {
- qCDebug(DBG_SHADER_CACHE) << "GL_RENDERER does not match" << renderer << info.glrenderer;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_RENDERER does not match" << renderer << info.glrenderer;
undertaker.setActive();
return false;
}
QByteArray version = readStr(&p);
if (version != info.glversion) {
- qCDebug(DBG_SHADER_CACHE) << "GL_VERSION does not match" << version << info.glversion;
+ qCDebug(lcOpenGLProgramDiskCache) << "GL_VERSION does not match" << version << info.glversion;
undertaker.setActive();
return false;
}
@@ -374,7 +388,7 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
const int totalSize = headerSize + paddingSize + blobSize;
- qCDebug(DBG_SHADER_CACHE, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary is %d bytes, err = 0x%x, total %d", blobSize, funcs->glGetError(), totalSize);
if (!blobSize)
return;
@@ -401,13 +415,14 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
GLint outSize = 0;
#if defined(QT_OPENGL_ES_2)
if (context->isOpenGLES() && context->format().majorVersion() < 3) {
+ QMutexLocker lock(&m_mutex);
initializeProgramBinaryOES(context);
getProgramBinaryOES(programId, blobSize, &outSize, &blobFormat, p);
} else
#endif
funcs->glGetProgramBinary(programId, blobSize, &outSize, &blobFormat, p);
if (blobSize != outSize) {
- qCDebug(DBG_SHADER_CACHE, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
+ qCDebug(lcOpenGLProgramDiskCache, "glGetProgramBinary returned size %d instead of %d", outSize, blobSize);
return;
}
@@ -423,9 +438,9 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(blob) < blob.length())
#endif
- qCDebug(DBG_SHADER_CACHE, "Failed to write %s to shader cache", qPrintable(f.fileName()));
+ qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
} else {
- qCDebug(DBG_SHADER_CACHE, "Failed to create %s in shader cache", qPrintable(f.fileName()));
+ qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
}
}
@@ -442,4 +457,45 @@ void QOpenGLProgramBinaryCache::initializeProgramBinaryOES(QOpenGLContext *conte
}
#endif
+QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
+ : QOpenGLSharedResource(context->shareGroup()),
+ m_supported(false)
+{
+ if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via app attribute");
+ return;
+ }
+ if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache disabled via env var");
+ return;
+ }
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (ctx) {
+ if (ctx->isOpenGLES()) {
+ qCDebug(lcOpenGLProgramDiskCache, "OpenGL ES v%d context", ctx->format().majorVersion());
+ if (ctx->format().majorVersion() >= 3) {
+ m_supported = true;
+ } else {
+ const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
+ qCDebug(lcOpenGLProgramDiskCache, "GL_OES_get_program_binary support = %d", hasExt);
+ if (hasExt)
+ m_supported = true;
+ }
+ } else {
+ const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
+ qCDebug(lcOpenGLProgramDiskCache, "GL_ARB_get_program_binary support = %d", hasExt);
+ if (hasExt)
+ m_supported = true;
+ }
+ if (m_supported) {
+ GLint fmtCount = 0;
+ ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
+ qCDebug(lcOpenGLProgramDiskCache, "Supported binary format count = %d", fmtCount);
+ m_supported = fmtCount > 0;
+ }
+ }
+ qCDebug(lcOpenGLProgramDiskCache, "Shader cache supported = %d", m_supported);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h
index 9fade08e66..f1cf24cd87 100644
--- a/src/gui/opengl/qopenglprogrambinarycache_p.h
+++ b/src/gui/opengl/qopenglprogrambinarycache_p.h
@@ -52,24 +52,31 @@
//
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qopenglshaderprogram.h>
#include <QtCore/qcache.h>
+#include <QtCore/qmutex.h>
+#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/private/qshader_p.h>
QT_BEGIN_NAMESPACE
+// These classes are also used by the OpenGL backend of QRhi. They must
+// therefore stay independent from QOpenGLShader(Program). Must rely only on
+// QOpenGLContext/Functions.
+
class QOpenGLProgramBinaryCache
{
public:
struct ShaderDesc {
ShaderDesc() { }
- ShaderDesc(QOpenGLShader::ShaderType type, const QByteArray &source = QByteArray())
- : type(type), source(source)
+ ShaderDesc(QShader::Stage stage, const QByteArray &source = QByteArray())
+ : stage(stage), source(source)
{ }
- QOpenGLShader::ShaderType type;
+ QShader::Stage stage;
QByteArray source;
};
struct ProgramDesc {
QVector<ShaderDesc> shaders;
+ QByteArray cacheKey() const;
};
QOpenGLProgramBinaryCache();
@@ -99,6 +106,37 @@ private:
void initializeProgramBinaryOES(QOpenGLContext *context);
bool m_programBinaryOESInitialized = false;
#endif
+ QMutex m_mutex;
+};
+
+// While unlikely, one application can in theory use contexts with different versions
+// or profiles. Therefore any version- or extension-specific checks must be done on a
+// per-context basis, not just once per process. QOpenGLSharedResource enables this,
+// although it's once-per-sharing-context-group, not per-context. Still, this should
+// be good enough in practice.
+class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
+{
+public:
+ QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
+ void invalidateResource() override { }
+ void freeResource(QOpenGLContext *) override { }
+
+ bool isSupported() const { return m_supported; }
+
+private:
+ bool m_supported;
+};
+
+class QOpenGLProgramBinarySupportCheckWrapper
+{
+public:
+ QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
+ {
+ return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
+ }
+
+private:
+ QOpenGLMultiGroupSharedResource m_resource;
};
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp
index 3c7bd4f90d..4986ca573d 100644
--- a/src/gui/opengl/qopenglshaderprogram.cpp
+++ b/src/gui/opengl/qopenglshaderprogram.cpp
@@ -47,8 +47,6 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
#include <QtCore/qloggingcategory.h>
-#include <QtCore/qcryptographichash.h>
-#include <QtCore/qcoreapplication.h>
#include <QtGui/qtransform.h>
#include <QtGui/QColor>
#include <QtGui/QSurfaceFormat>
@@ -179,7 +177,7 @@ QT_BEGIN_NAMESPACE
(requires OpenGL >= 4.3 or OpenGL ES >= 3.1).
*/
-Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
+Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
// For GLES 3.1/3.2
#ifndef GL_GEOMETRY_SHADER
@@ -210,10 +208,6 @@ Q_LOGGING_CATEGORY(DBG_SHADER_CACHE, "qt.opengl.diskcache")
#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
#endif
-#ifndef GL_NUM_PROGRAM_BINARY_FORMATS
-#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
-#endif
-
#ifndef QT_OPENGL_ES_2
static inline bool isFormatGLES(const QSurfaceFormat &f)
{
@@ -1081,6 +1075,44 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
return addCacheableShaderFromSourceCode(type, QByteArray(source));
}
+static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type)
+{
+ switch (type) {
+ case QOpenGLShader::Vertex:
+ return QShader::VertexStage;
+ case QOpenGLShader::Fragment:
+ return QShader::FragmentStage;
+ case QOpenGLShader::Geometry:
+ return QShader::GeometryStage;
+ case QOpenGLShader::TessellationControl:
+ return QShader::TessellationControlStage;
+ case QOpenGLShader::TessellationEvaluation:
+ return QShader::TessellationEvaluationStage;
+ case QOpenGLShader::Compute:
+ return QShader::ComputeStage;
+ }
+ return QShader::VertexStage;
+}
+
+static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage)
+{
+ switch (stage) {
+ case QShader::VertexStage:
+ return QOpenGLShader::Vertex;
+ case QShader::TessellationControlStage:
+ return QOpenGLShader::TessellationControl;
+ case QShader::TessellationEvaluationStage:
+ return QOpenGLShader::TessellationEvaluation;
+ case QShader::GeometryStage:
+ return QOpenGLShader::Geometry;
+ case QShader::FragmentStage:
+ return QOpenGLShader::Fragment;
+ case QShader::ComputeStage:
+ return QOpenGLShader::Compute;
+ }
+ return QOpenGLShader::Vertex;
+}
+
/*!
\overload
@@ -1109,7 +1141,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceCode(type, source);
- d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(type, source));
+ d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source));
return true;
}
@@ -1166,7 +1198,7 @@ bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::Shade
if (d->isCacheDisabled())
return addShaderFromSourceFile(type, fileName);
- QOpenGLProgramBinaryCache::ShaderDesc shader(type);
+ QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type));
// NB! It could be tempting to defer reading the file contents and just
// hash the filename as the cache key, perhaps combined with last-modified
// timestamp checks. However, this would raise a number of issues (no
@@ -3720,77 +3752,6 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context)
return true;
}
-// While unlikely, one application can in theory use contexts with different versions
-// or profiles. Therefore any version- or extension-specific checks must be done on a
-// per-context basis, not just once per process. QOpenGLSharedResource enables this,
-// although it's once-per-sharing-context-group, not per-context. Still, this should
-// be good enough in practice.
-class QOpenGLProgramBinarySupportCheck : public QOpenGLSharedResource
-{
-public:
- QOpenGLProgramBinarySupportCheck(QOpenGLContext *context);
- void invalidateResource() override { }
- void freeResource(QOpenGLContext *) override { }
-
- bool isSupported() const { return m_supported; }
-
-private:
- bool m_supported;
-};
-
-QOpenGLProgramBinarySupportCheck::QOpenGLProgramBinarySupportCheck(QOpenGLContext *context)
- : QOpenGLSharedResource(context->shareGroup()),
- m_supported(false)
-{
- if (QCoreApplication::testAttribute(Qt::AA_DisableShaderDiskCache)) {
- qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via app attribute");
- return;
- }
- if (qEnvironmentVariableIntValue("QT_DISABLE_SHADER_DISK_CACHE")) {
- qCDebug(DBG_SHADER_CACHE, "Shader cache disabled via env var");
- return;
- }
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (ctx) {
- if (ctx->isOpenGLES()) {
- qCDebug(DBG_SHADER_CACHE, "OpenGL ES v%d context", ctx->format().majorVersion());
- if (ctx->format().majorVersion() >= 3) {
- m_supported = true;
- } else {
- const bool hasExt = ctx->hasExtension("GL_OES_get_program_binary");
- qCDebug(DBG_SHADER_CACHE, "GL_OES_get_program_binary support = %d", hasExt);
- if (hasExt)
- m_supported = true;
- }
- } else {
- const bool hasExt = ctx->hasExtension("GL_ARB_get_program_binary");
- qCDebug(DBG_SHADER_CACHE, "GL_ARB_get_program_binary support = %d", hasExt);
- if (hasExt)
- m_supported = true;
- }
- if (m_supported) {
- GLint fmtCount = 0;
- ctx->functions()->glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &fmtCount);
- qCDebug(DBG_SHADER_CACHE, "Supported binary format count = %d", fmtCount);
- m_supported = fmtCount > 0;
- }
- }
- qCDebug(DBG_SHADER_CACHE, "Shader cache supported = %d", m_supported);
-}
-
-class QOpenGLProgramBinarySupportCheckWrapper
-{
-public:
- QOpenGLProgramBinarySupportCheck *get(QOpenGLContext *context)
- {
- return m_resource.value<QOpenGLProgramBinarySupportCheck>(context);
- }
-
-private:
- QOpenGLMultiGroupSharedResource m_resource;
-};
-
bool QOpenGLShaderProgramPrivate::isCacheDisabled() const
{
static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck;
@@ -3801,7 +3762,7 @@ bool QOpenGLShaderProgramPrivate::compileCacheable()
{
Q_Q(QOpenGLShaderProgram);
for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) {
- QScopedPointer<QOpenGLShader> s(new QOpenGLShader(shader.type, q));
+ QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q));
if (!s->compileSourceCode(shader.source)) {
log = s->log();
return false;
@@ -3819,24 +3780,20 @@ bool QOpenGLShaderProgramPrivate::linkBinary()
Q_Q(QOpenGLShaderProgram);
- QCryptographicHash keyBuilder(QCryptographicHash::Sha1);
- for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders))
- keyBuilder.addData(shader.source);
-
- const QByteArray cacheKey = keyBuilder.result().toHex();
- if (DBG_SHADER_CACHE().isEnabled(QtDebugMsg))
- qCDebug(DBG_SHADER_CACHE, "program with %d shaders, cache key %s",
+ const QByteArray cacheKey = binaryProgram.cacheKey();
+ if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg))
+ qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s",
binaryProgram.shaders.count(), cacheKey.constData());
bool needsCompile = true;
if (binCache.load(cacheKey, q->programId())) {
- qCDebug(DBG_SHADER_CACHE, "Program binary received from cache");
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache");
needsCompile = false;
}
bool needsSave = false;
if (needsCompile) {
- qCDebug(DBG_SHADER_CACHE, "Program binary not in cache, compiling");
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling");
if (compileCacheable())
needsSave = true;
else
diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp
index 61a6202017..ed58766dde 100644
--- a/src/gui/opengl/qopengltexture.cpp
+++ b/src/gui/opengl/qopengltexture.cpp
@@ -4612,7 +4612,7 @@ QOpenGLTexture::WrapMode QOpenGLTexture::wrapMode(QOpenGLTexture::CoordinateDire
\note This function has no effect on Mac and Qt built for OpenGL ES 2.
\sa borderColor()
*/
-void QOpenGLTexture::setBorderColor(QColor color)
+void QOpenGLTexture::setBorderColor(const QColor &color)
{
setBorderColor(static_cast<float>(color.redF()), static_cast<float>(color.greenF()),
static_cast<float>(color.blueF()), static_cast<float>(color.alphaF()));
diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h
index 7d984babc8..539b6aa7b2 100644
--- a/src/gui/opengl/qopengltexture.h
+++ b/src/gui/opengl/qopengltexture.h
@@ -621,7 +621,7 @@ public:
void setWrapMode(CoordinateDirection direction, WrapMode mode);
WrapMode wrapMode(CoordinateDirection direction) const;
- void setBorderColor(QColor color);
+ void setBorderColor(const QColor &color);
void setBorderColor(float r, float g, float b, float a);
void setBorderColor(int r, int g, int b, int a);
void setBorderColor(uint r, uint g, uint b, uint a);
diff --git a/src/gui/painting/XCONSORTIUM_LICENSE.txt b/src/gui/painting/XCONSORTIUM_LICENSE.txt
new file mode 100644
index 0000000000..5d98625787
--- /dev/null
+++ b/src/gui/painting/XCONSORTIUM_LICENSE.txt
@@ -0,0 +1,43 @@
+Copyright (c) 1987, 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 3240b83451..b0393aff95 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -95,6 +95,11 @@ public:
QBackingStore::QBackingStore(QWindow *window)
: d_ptr(new QBackingStorePrivate(window))
{
+ if (window->handle()) {
+ // Create platform backingstore up front if we have a platform window,
+ // otherwise delay the creation until absolutely necessary.
+ handle();
+ }
}
/*!
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index 9861fffff3..7622262da9 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -106,10 +106,10 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold
int levels[10];
beziers[0] = *this;
levels[0] = 9;
- QBezier *b = beziers;
- int *lvl = levels;
+ int top = 0;
- while (b >= beziers) {
+ while (top >= 0) {
+ QBezier *b = &beziers[top];
// check if we can pop the top bezier curve from the stack
qreal y4y1 = b->y4 - b->y1;
qreal x4x1 = b->x4 - b->x1;
@@ -123,17 +123,15 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold
qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
l = 1.;
}
- if (d < bezier_flattening_threshold*l || *lvl == 0) {
+ if (d < bezier_flattening_threshold * l || levels[top] == 0) {
// good enough, we pop it off and add the endpoint
polygon->append(QPointF(b->x4, b->y4));
- --b;
- --lvl;
+ --top;
} else {
// split, second half of the polygon goes lower into the stack
std::tie(b[1], b[0]) = b->split();
- lvl[1] = --lvl[0];
- ++b;
- ++lvl;
+ levels[top + 1] = --levels[top];
+ ++top;
}
}
}
@@ -144,10 +142,10 @@ void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattenin
int levels[10];
beziers[0] = *this;
levels[0] = 9;
- QBezier *b = beziers;
- int *lvl = levels;
+ int top = 0;
- while (b >= beziers) {
+ while (top >= 0) {
+ QBezier *b = &beziers[top];
// check if we can pop the top bezier curve from the stack
qreal y4y1 = b->y4 - b->y1;
qreal x4x1 = b->x4 - b->x1;
@@ -161,17 +159,15 @@ void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattenin
qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
l = 1.;
}
- if (d < bezier_flattening_threshold*l || *lvl == 0) {
+ if (d < bezier_flattening_threshold * l || levels[top] == 0) {
// good enough, we pop it off and add the endpoint
polygon.add(QPointF(b->x4, b->y4));
- --b;
- --lvl;
+ --top;
} else {
// split, second half of the polygon goes lower into the stack
std::tie(b[1], b[0]) = b->split();
- lvl[1] = --lvl[0];
- ++b;
- ++lvl;
+ levels[top + 1] = --levels[top];
+ ++top;
}
}
}
diff --git a/src/gui/painting/qcolormatrix_p.h b/src/gui/painting/qcolormatrix_p.h
index 66db95df7e..edb2d32258 100644
--- a/src/gui/painting/qcolormatrix_p.h
+++ b/src/gui/painting/qcolormatrix_p.h
@@ -62,17 +62,16 @@ class QColorVector
{
public:
QColorVector() = default;
- Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z), _unused(0.0f) { }
+ Q_DECL_CONSTEXPR QColorVector(float x, float y, float z) : x(x), y(y), z(z) { }
explicit Q_DECL_CONSTEXPR QColorVector(const QPointF &chr) // from XY chromaticity
: x(chr.x() / chr.y())
, y(1.0f)
, z((1.0 - chr.x() - chr.y()) / chr.y())
- , _unused(0.0f)
{ }
- float x; // X, x or red
- float y; // Y, y or green
- float z; // Z, Y or blue
- float _unused;
+ float x = 0.0f; // X, x or red
+ float y = 0.0f; // Y, y or green
+ float z = 0.0f; // Z, Y or blue
+ float _unused = 0.0f;
friend inline bool operator==(const QColorVector &v1, const QColorVector &v2);
friend inline bool operator!=(const QColorVector &v1, const QColorVector &v2);
@@ -81,7 +80,6 @@ public:
return !x && !y && !z;
}
- static Q_DECL_CONSTEXPR QColorVector null() { return QColorVector(0.0f, 0.0f, 0.0f); }
static bool isValidChromaticity(const QPointF &chr)
{
if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0))
@@ -187,10 +185,6 @@ public:
{ r.z, g.z, b.z } };
}
- static QColorMatrix null()
- {
- return { QColorVector::null(), QColorVector::null(), QColorVector::null() };
- }
static QColorMatrix identity()
{
return { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } };
@@ -226,12 +220,6 @@ public:
{ 0.1351922452f, 0.7118769884f, 0.0000000000f },
{ 0.0313525312f, 0.0000856627f, 0.8251883388f } };
}
- static QColorMatrix toXyzFromBt2020()
- {
- return QColorMatrix { { 0.6506130099f, 0.2695676684f, -0.0018652577f },
- { 0.1865101457f, 0.6840794086f, 0.0172256753f },
- { 0.1270887405f, 0.0463530831f, 0.8098278046f } };
- }
};
inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2)
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 86d0c57cfe..937bb505c9 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -70,12 +70,6 @@ QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries)
bluePoint = QPointF(0.150, 0.060);
whitePoint = QColorVector::D65Chromaticity();
break;
- case QColorSpace::Primaries::Bt2020:
- redPoint = QPointF(0.708, 0.292);
- greenPoint = QPointF(0.190, 0.797);
- bluePoint = QPointF(0.131, 0.046);
- whitePoint = QColorVector::D65Chromaticity();
- break;
case QColorSpace::Primaries::AdobeRgb:
redPoint = QPointF(0.640, 0.330);
greenPoint = QPointF(0.210, 0.710);
@@ -152,25 +146,13 @@ QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
}
QColorSpacePrivate::QColorSpacePrivate()
- : id(QColorSpace::Unknown)
- , primaries(QColorSpace::Primaries::Custom)
- , transferFunction(QColorSpace::TransferFunction::Custom)
- , gamma(0.0f)
- , whitePoint(QColorVector::null())
- , toXyz(QColorMatrix::null())
{
}
-QColorSpacePrivate::QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId)
- : id(colorSpaceId)
- , gamma(0.0f)
+QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
+ : namedColorSpace(namedColorSpace)
{
- switch (colorSpaceId) {
- case QColorSpace::Undefined:
- primaries = QColorSpace::Primaries::Custom;
- transferFunction = QColorSpace::TransferFunction::Custom;
- description = QStringLiteral("Undefined");
- break;
+ switch (namedColorSpace) {
case QColorSpace::SRgb:
primaries = QColorSpace::Primaries::SRgb;
transferFunction = QColorSpace::TransferFunction::SRgb;
@@ -197,14 +179,6 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId)
transferFunction = QColorSpace::TransferFunction::ProPhotoRgb;
description = QStringLiteral("ProPhoto RGB");
break;
- case QColorSpace::Bt2020:
- primaries = QColorSpace::Primaries::Bt2020;
- transferFunction = QColorSpace::TransferFunction::Bt2020;
- description = QStringLiteral("BT.2020");
- break;
- case QColorSpace::Unknown:
- qWarning("Can not create an unknown color space");
- Q_FALLTHROUGH();
default:
Q_UNREACHABLE();
}
@@ -216,8 +190,7 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorS
, transferFunction(fun)
, gamma(gamma)
{
- if (!identifyColorSpace())
- id = QColorSpace::Unknown;
+ identifyColorSpace();
initialize();
}
@@ -235,71 +208,63 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
setTransferFunction();
}
-bool QColorSpacePrivate::identifyColorSpace()
+void QColorSpacePrivate::identifyColorSpace()
{
switch (primaries) {
case QColorSpace::Primaries::SRgb:
if (transferFunction == QColorSpace::TransferFunction::SRgb) {
- id = QColorSpace::SRgb;
+ namedColorSpace = QColorSpace::SRgb;
if (description.isEmpty())
description = QStringLiteral("sRGB");
- return true;
+ return;
}
if (transferFunction == QColorSpace::TransferFunction::Linear) {
- id = QColorSpace::SRgbLinear;
+ namedColorSpace = QColorSpace::SRgbLinear;
if (description.isEmpty())
description = QStringLiteral("Linear sRGB");
- return true;
+ return;
}
break;
case QColorSpace::Primaries::AdobeRgb:
if (transferFunction == QColorSpace::TransferFunction::Gamma) {
if (qAbs(gamma - 2.19921875f) < (1/1024.0f)) {
- id = QColorSpace::AdobeRgb;
+ namedColorSpace = QColorSpace::AdobeRgb;
if (description.isEmpty())
description = QStringLiteral("Adobe RGB");
- return true;
+ return;
}
}
break;
case QColorSpace::Primaries::DciP3D65:
if (transferFunction == QColorSpace::TransferFunction::SRgb) {
- id = QColorSpace::DisplayP3;
+ namedColorSpace = QColorSpace::DisplayP3;
if (description.isEmpty())
description = QStringLiteral("Display P3");
- return true;
+ return;
}
break;
case QColorSpace::Primaries::ProPhotoRgb:
if (transferFunction == QColorSpace::TransferFunction::ProPhotoRgb) {
- id = QColorSpace::ProPhotoRgb;
+ namedColorSpace = QColorSpace::ProPhotoRgb;
if (description.isEmpty())
description = QStringLiteral("ProPhoto RGB");
- return true;
+ return;
}
if (transferFunction == QColorSpace::TransferFunction::Gamma) {
// ProPhoto RGB's curve is effectively gamma 1.8 for 8bit precision.
if (qAbs(gamma - 1.8f) < (1/1024.0f)) {
- id = QColorSpace::ProPhotoRgb;
+ namedColorSpace = QColorSpace::ProPhotoRgb;
if (description.isEmpty())
description = QStringLiteral("ProPhoto RGB");
- return true;
+ return;
}
}
break;
- case QColorSpace::Primaries::Bt2020:
- if (transferFunction == QColorSpace::TransferFunction::Bt2020) {
- id = QColorSpace::Bt2020;
- if (description.isEmpty())
- description = QStringLiteral("BT.2020");
- return true;
- }
- break;
default:
break;
}
- id = QColorSpace::Unknown;
- return false;
+
+ namedColorSpace = Unknown;
}
void QColorSpacePrivate::initialize()
@@ -311,7 +276,7 @@ void QColorSpacePrivate::initialize()
void QColorSpacePrivate::setToXyzMatrix()
{
if (primaries == QColorSpace::Primaries::Custom) {
- toXyz = QColorMatrix::null();
+ toXyz = QColorMatrix();
whitePoint = QColorVector::D50();
return;
}
@@ -345,12 +310,6 @@ void QColorSpacePrivate::setTransferFunction()
if (qFuzzyIsNull(gamma))
gamma = 1.8f;
break;
- case QColorSpace::TransferFunction::Bt2020:
- trc[0].m_type = QColorTrc::Type::Function;
- trc[0].m_fun = QColorTransferFunction::fromBt2020();
- if (qFuzzyIsNull(gamma))
- gamma = 1.961f;
- break;
case QColorSpace::TransferFunction::Custom:
break;
default:
@@ -410,12 +369,10 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
/*!
- \enum QColorSpace::ColorSpaceId
+ \enum QColorSpace::NamedColorSpace
Predefined color spaces.
- \value Undefined An empty, invalid or unsupported color space.
- \value Unknown A valid color space that doesn't match any of the predefined color spaces.
\value SRgb The sRGB color space, which Qt operates in by default. It is a close approximation
of how most classic monitors operate, and a mode most software and hardware support.
\l{http://www.color.org/chardata/rgb/srgb.xalter}{ICC registration of sRGB}.
@@ -427,8 +384,6 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\l{http://www.color.org/chardata/rgb/DCIP3.xalter}{ICC registration of DCI-P3}
\value ProPhotoRgb The Pro Photo RGB color space, also known as ROMM RGB is a very wide gamut color space.
\l{http://www.color.org/chardata/rgb/rommrgb.xalter}{ICC registration of ROMM RGB}
- \value Bt2020 BT.2020 also known as Rec.2020 is the color space of HDR TVs.
- \l{http://www.color.org/chardata/rgb/BT2020.xalter}{ICC registration of BT.2020}
*/
/*!
@@ -441,7 +396,6 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\value AdobeRgb The Adobe RGB primaries
\value DciP3D65 The DCI-P3 primaries with the D65 whitepoint
\value ProPhotoRgb The ProPhoto RGB primaries with the D50 whitepoint
- \value Bt2020 The BT.2020 primaries
*/
/*!
@@ -454,26 +408,28 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
\value Gamma A transfer function that is a real gamma curve based on the value of gamma()
\value SRgb The sRGB transfer function, composed of linear and gamma parts
\value ProPhotoRgb The ProPhoto RGB transfer function, composed of linear and gamma parts
- \value Bt2020 The BT.2020 transfer function, composed of linear and gamma parts
*/
/*!
- Creates a new colorspace object that represents \a colorSpaceId.
+ Creates a new colorspace object that represents an undefined and invalid colorspace.
*/
-QColorSpace::QColorSpace(QColorSpace::ColorSpaceId colorSpaceId)
- : d_ptr(nullptr)
-{
- static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::Bt2020];
- // Unknown and undefined both returns the static undefined colorspace
- if (colorSpaceId > QColorSpace::Unknown) {
- if (!predefinedColorspacePrivates[colorSpaceId - 2]) {
- predefinedColorspacePrivates[colorSpaceId - 2] = new QColorSpacePrivate(colorSpaceId);
- predefinedColorspacePrivates[colorSpaceId - 2]->ref.ref();
- }
- d_ptr = predefinedColorspacePrivates[colorSpaceId - 2];
- d_ptr->ref.ref();
- Q_ASSERT(isValid());
+QColorSpace::QColorSpace()
+{
+}
+
+/*!
+ Creates a new colorspace object that represents a \a namedColorSpace.
+ */
+QColorSpace::QColorSpace(NamedColorSpace namedColorSpace)
+{
+ static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1];
+ if (!predefinedColorspacePrivates[namedColorSpace]) {
+ predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace);
+ predefinedColorspacePrivates[namedColorSpace]->ref.ref();
}
+ d_ptr = predefinedColorspacePrivates[namedColorSpace];
+ d_ptr->ref.ref();
+ Q_ASSERT(isValid());
}
/*!
@@ -545,17 +501,6 @@ QColorSpace &QColorSpace::operator=(const QColorSpace &colorSpace)
*/
/*!
- Returns the id of the predefined color space this object
- represents or \c Unknown if it doesn't match any of them.
-*/
-QColorSpace::ColorSpaceId QColorSpace::colorSpaceId() const noexcept
-{
- if (Q_UNLIKELY(!d_ptr))
- return QColorSpace::Undefined;
- return d_ptr->id;
-}
-
-/*!
Returns the predefined primaries of the color space
or \c primaries::Custom if it doesn't match any of them.
*/
@@ -596,8 +541,6 @@ float QColorSpace::gamma() const noexcept
/*!
Sets the transfer function to \a transferFunction and \a gamma.
- \note This also changes colorSpaceId().
-
\sa transferFunction(), gamma(), withTransferFunction()
*/
void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunction, float gamma)
@@ -634,8 +577,6 @@ QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction tran
/*!
Sets the primaries to those of the \a primariesId set.
- \note This also changes colorSpaceId().
-
\sa primaries()
*/
void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
@@ -655,8 +596,6 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
Set primaries to the chromaticities of \a whitePoint, \a redPoint, \a greenPoint
and \a bluePoint.
- \note This also changes colorSpaceId().
-
\sa primaries()
*/
void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoint,
@@ -718,7 +657,6 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
if (QIcc::fromIccProfile(iccProfile, &colorSpace))
return colorSpace;
QColorSpacePrivate *d = QColorSpacePrivate::getWritable(colorSpace);
- d->id = QColorSpace::Undefined;
d->iccProfile = iccProfile;
return colorSpace;
}
@@ -728,7 +666,8 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
*/
bool QColorSpace::isValid() const noexcept
{
- return d_ptr && d_ptr->id != QColorSpace::Undefined && d_ptr->toXyz.isValid()
+ return d_ptr
+ && d_ptr->toXyz.isValid()
&& d_ptr->trc[0].isValid() && d_ptr->trc[1].isValid() && d_ptr->trc[2].isValid();
}
@@ -744,11 +683,17 @@ bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
if (!colorSpace1.d_ptr || !colorSpace2.d_ptr)
return false;
- if (colorSpace1.colorSpaceId() == QColorSpace::Undefined && colorSpace2.colorSpaceId() == QColorSpace::Undefined)
+ if (colorSpace1.d_ptr->namedColorSpace && colorSpace2.d_ptr->namedColorSpace)
+ return colorSpace1.d_ptr->namedColorSpace == colorSpace2.d_ptr->namedColorSpace;
+
+ const bool valid1 = colorSpace1.isValid();
+ const bool valid2 = colorSpace2.isValid();
+ if (!valid1 && !valid2)
return colorSpace1.d_ptr->iccProfile == colorSpace2.d_ptr->iccProfile;
+ else if (!valid1 || !valid2)
+ return false;
- if (colorSpace1.colorSpaceId() != QColorSpace::Unknown && colorSpace2.colorSpaceId() != QColorSpace::Unknown)
- return colorSpace1.colorSpaceId() == colorSpace2.colorSpaceId();
+ // At this point one or both color spaces are unknown but valid, and must be compared in detail instead
if (colorSpace1.primaries() != QColorSpace::Primaries::Custom && colorSpace2.primaries() != QColorSpace::Primaries::Custom) {
if (colorSpace1.primaries() != colorSpace2.primaries())
@@ -839,7 +784,9 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg << "QColorSpace(";
- dbg << colorSpace.colorSpaceId() << ", " << colorSpace.primaries() << ", " << colorSpace.transferFunction();
+ if (colorSpace.d_ptr->namedColorSpace)
+ dbg << colorSpace.d_ptr->namedColorSpace << ", ";
+ dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
dbg << ", gamma=" << colorSpace.gamma();
dbg << ')';
return dbg;
diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h
index 880f0ad4cf..e6bc62d58a 100644
--- a/src/gui/painting/qcolorspace.h
+++ b/src/gui/painting/qcolorspace.h
@@ -54,24 +54,20 @@ class Q_GUI_EXPORT QColorSpace
{
Q_GADGET
public:
- enum ColorSpaceId {
- Undefined = 0,
- Unknown = 1,
- SRgb,
+ enum NamedColorSpace {
+ SRgb = 1,
SRgbLinear,
AdobeRgb,
DisplayP3,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
- Q_ENUM(ColorSpaceId)
+ Q_ENUM(NamedColorSpace)
enum class Primaries {
Custom = 0,
SRgb,
AdobeRgb,
DciP3D65,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
Q_ENUM(Primaries)
enum class TransferFunction {
@@ -79,12 +75,12 @@ public:
Linear,
Gamma,
SRgb,
- ProPhotoRgb,
- Bt2020,
+ ProPhotoRgb
};
Q_ENUM(TransferFunction)
- QColorSpace(ColorSpaceId colorSpaceId = Undefined);
+ QColorSpace();
+ QColorSpace(NamedColorSpace namedColorSpace);
QColorSpace(Primaries primaries, TransferFunction fun, float gamma = 0.0f);
QColorSpace(Primaries primaries, float gamma);
QColorSpace(const QPointF &whitePoint, const QPointF &redPoint,
@@ -108,7 +104,6 @@ public:
void swap(QColorSpace &colorSpace) noexcept
{ qSwap(d_ptr, colorSpace.d_ptr); }
- ColorSpaceId colorSpaceId() const noexcept;
Primaries primaries() const noexcept;
TransferFunction transferFunction() const noexcept;
float gamma() const noexcept;
@@ -133,7 +128,11 @@ public:
private:
Q_DECLARE_PRIVATE(QColorSpace)
- QColorSpacePrivate *d_ptr;
+ QColorSpacePrivate *d_ptr = nullptr;
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace);
+#endif
};
bool Q_GUI_EXPORT operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2);
diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h
index 037111a0ae..e7add19ed3 100644
--- a/src/gui/painting/qcolorspace_p.h
+++ b/src/gui/painting/qcolorspace_p.h
@@ -62,7 +62,7 @@
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QColorSpacePrimaries
+class Q_AUTOTEST_EXPORT QColorSpacePrimaries
{
public:
QColorSpacePrimaries() = default;
@@ -90,7 +90,7 @@ class QColorSpacePrivate : public QSharedData
{
public:
QColorSpacePrivate();
- QColorSpacePrivate(QColorSpace::ColorSpaceId colorSpaceId);
+ QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace);
QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction fun, float gamma);
QColorSpacePrivate(const QColorSpacePrimaries &primaries, QColorSpace::TransferFunction fun, float gamma);
QColorSpacePrivate(const QColorSpacePrivate &other) = default;
@@ -118,13 +118,15 @@ public:
void initialize();
void setToXyzMatrix();
void setTransferFunction();
- bool identifyColorSpace();
+ void identifyColorSpace();
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const;
- QColorSpace::ColorSpaceId id;
- QColorSpace::Primaries primaries;
- QColorSpace::TransferFunction transferFunction;
- float gamma;
+ static constexpr QColorSpace::NamedColorSpace Unknown = QColorSpace::NamedColorSpace(0);
+ QColorSpace::NamedColorSpace namedColorSpace = Unknown;
+
+ QColorSpace::Primaries primaries = QColorSpace::Primaries::Custom;
+ QColorSpace::TransferFunction transferFunction = QColorSpace::TransferFunction::Custom;
+ float gamma = 0.0f;
QColorVector whitePoint;
QColorTrc trc[3];
diff --git a/src/gui/painting/qcolortransferfunction_p.h b/src/gui/painting/qcolortransferfunction_p.h
index fd7cfa2b2b..0575dbd888 100644
--- a/src/gui/painting/qcolortransferfunction_p.h
+++ b/src/gui/painting/qcolortransferfunction_p.h
@@ -130,10 +130,6 @@ public:
{
return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f);
}
- static QColorTransferFunction fromBt2020()
- {
- return QColorTransferFunction(1.0f / 1.0993f, 0.0993f / 1.0993f, 1.0f / 4.5f, 0.08145f, 0.0f, 0.0f, 2.2f);
- }
static QColorTransferFunction fromProPhotoRgb()
{
return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f);
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index 53fd1dfbaa..10ccefed74 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -612,6 +612,15 @@ static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *bu
static constexpr qsizetype WorkBlockSize = 256;
+template <typename T, int Count = 1>
+class QUninitialized
+{
+public:
+ operator T*() { return reinterpret_cast<T *>(this); }
+private:
+ alignas(T) char data[sizeof(T) * Count];
+};
+
template<typename T>
void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const
{
@@ -623,7 +632,8 @@ void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, Transf
bool doApplyMatrix = (colorMatrix != QColorMatrix::identity());
- QColorVector buffer[WorkBlockSize];
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
qsizetype i = 0;
while (i < count) {
const qsizetype len = qMin(count - i, WorkBlockSize);
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index c17bf2ddfd..e5f752b94e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -669,8 +669,7 @@ static void QT_FASTCALL rbSwap_rgb30(uchar *d, const uchar *s, int count)
{
const uint *src = reinterpret_cast<const uint *>(s);
uint *dest = reinterpret_cast<uint *>(d);
- for (int i = 0; i < count; ++i)
- dest[i] = qRgbSwapRgb30(src[i]);
+ UNALIASED_CONVERSION_LOOP(dest, src, count, qRgbSwapRgb30);
}
template<QImage::Format Format> Q_DECL_CONSTEXPR static inline QPixelLayout pixelLayoutRGB()
@@ -5659,44 +5658,63 @@ static inline void alphamapblend_argb32(quint32 *dst, int coverage, QRgba64 srcL
{
if (coverage == 0) {
// nothing
- } else if (coverage == 255) {
- *dst = src;
- } else if (!colorProfile) {
- *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage);
+ } else if (coverage == 255 || !colorProfile) {
+ blend_pixel(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, coverage);
+ } else if (src >= 0xff000000) {
+ grayBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
- if (*dst >= 0xff000000) {
- grayBlendPixel(dst, coverage, srcLinear, colorProfile);
- } else {
- // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
- *dst = INTERPOLATE_PIXEL_255(src, coverage, *dst, 255 - coverage);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
+ grayBlendPixel(dst, coverage, s64, colorProfile);
}
}
#if QT_CONFIG(raster_64bit)
+
+static inline void grayBlendPixel(QRgba64 &dst, int coverage, QRgba64 srcLinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected gray alphablend...
+ QRgba64 dstColor = dst;
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->toLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+
+ blend_pixel(dstColor, srcLinear, coverage);
+
+ if (colorProfile) {
+ if (dstColor.isOpaque())
+ dstColor = colorProfile->fromLinear(dstColor);
+ else if (!dstColor.isTransparent())
+ dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
+ }
+ dst = dstColor;
+}
+
static inline void alphamapblend_generic(int coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0) {
// nothing
} else if (coverage == 255) {
- dest[x] = src;
+ blend_pixel(dest[x], src);
+ } else if (src.isOpaque()) {
+ grayBlendPixel(dest[x], coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->toLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->toLinear(dstColor.unpremultiplied()).premultiplied();
- }
-
- dstColor = interpolate255(srcLinear, coverage, dstColor, 255 - coverage);
- if (colorProfile) {
- if (dstColor.isOpaque())
- dstColor = colorProfile->fromLinear(dstColor);
- else if (!dstColor.isTransparent())
- dstColor = colorProfile->fromLinear(dstColor.unpremultiplied()).premultiplied();
- }
- dest[x] = dstColor;
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ if (colorProfile)
+ s = colorProfile->toLinear(s);
+ grayBlendPixel(dest[x], coverage, s, colorProfile);
}
}
@@ -5715,12 +5733,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -5793,12 +5807,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -5873,7 +5883,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
int mapWidth, int mapHeight, int mapStride,
const QClipData *clip, bool useGammaCorrection)
{
- if (useGammaCorrection) {
+ if (useGammaCorrection || !color.isOpaque()) {
qt_alphamapblit_generic(rasterBuffer, x, y, color, map, mapWidth, mapHeight, mapStride, clip, useGammaCorrection);
return;
}
@@ -5932,12 +5942,8 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA8Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -6032,48 +6038,62 @@ static inline QRgb rgbBlend(QRgb d, QRgb s, uint rgbAlpha)
#endif
}
-#if QT_CONFIG(raster_64bit)
-static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
+static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
- } else if (coverage == 0xffffffff) {
- dest[x] = src;
+ } else if (coverage == 0xffffffff && qAlpha(src) == 255) {
+ blend_pixel(*dst, src);
+ } else if (!colorProfile) {
+ *dst = rgbBlend(*dst, src, coverage);
+ } else if (*dst < 0xff000000) {
+ // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
+ blend_pixel(*dst, src, qRgbAvg(coverage));
+ } else if (srcLinear.isOpaque()) {
+ rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
} else {
- QRgba64 dstColor = dest[x];
- if (dstColor.isOpaque()) {
- if (colorProfile)
- dstColor = colorProfile->toLinear(dstColor);
- dstColor = rgbBlend(dstColor, srcLinear, coverage);
- if (colorProfile)
- dstColor = colorProfile->fromLinear(dstColor);
- dest[x] = dstColor;
- } else {
- // Do a gray alphablend.
- alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
- }
+ // First do naive blend with text-color
+ QRgb s = *dst;
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ QRgba64 s64 = colorProfile ? colorProfile->toLinear64(s) : QRgba64::fromArgb32(s);
+ rgbBlendPixel(dst, coverage, s64, colorProfile);
}
}
-#endif
-static inline void alphargbblend_argb32(quint32 *dst, uint coverage, const QRgba64 &srcLinear, quint32 src, const QColorTrcLut *colorProfile)
+#if QT_CONFIG(raster_64bit)
+static inline void rgbBlendPixel(QRgba64 &dst, int coverage, QRgba64 slinear, const QColorTrcLut *colorProfile)
+{
+ // Do a gammacorrected RGB alphablend...
+ const QRgba64 dlinear = colorProfile ? colorProfile->toLinear64(dst) : dst;
+
+ QRgba64 blend = rgbBlend(dlinear, slinear, coverage);
+
+ dst = colorProfile ? colorProfile->fromLinear(blend) : blend;
+}
+
+static inline void alphargbblend_generic(uint coverage, QRgba64 *dest, int x, const QRgba64 &srcLinear, const QRgba64 &src, const QColorTrcLut *colorProfile)
{
if (coverage == 0xff000000) {
// nothing
} else if (coverage == 0xffffffff) {
- *dst = src;
- } else if (*dst < 0xff000000) {
- // Give up and do a naive gray alphablend. Needed to deal with ARGB32 and invalid ARGB32_premultiplied, see QTBUG-60571
- const int a = qRgbAvg(coverage);
- *dst = INTERPOLATE_PIXEL_255(src, a, *dst, 255 - a);
- } else if (!colorProfile) {
- *dst = rgbBlend(*dst, src, coverage);
- } else {
- rgbBlendPixel(dst, coverage, srcLinear, colorProfile);
+ blend_pixel(dest[x], src);
+ } else if (!dest[x].isOpaque()) {
+ // Do a gray alphablend.
+ alphamapblend_generic(qRgbAvg(coverage), dest, x, srcLinear, src, colorProfile);
+ } else if (src.isOpaque()) {
+ rgbBlendPixel(dest[x], coverage, srcLinear, colorProfile);
+ } else {
+ // First do naive blend with text-color
+ QRgba64 s = dest[x];
+ blend_pixel(s, src);
+ // Then gamma-corrected blend with glyph shape
+ if (colorProfile)
+ s = colorProfile->toLinear(s);
+ rgbBlendPixel(dest[x], coverage, s, colorProfile);
}
}
-#if QT_CONFIG(raster_64bit)
static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
int x, int y, const QRgba64 &color,
const uint *src, int mapWidth, int mapHeight, int srcStride,
@@ -6088,12 +6108,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
alignas(8) QRgba64 buffer[BufferSize];
const DestFetchProc64 destFetch64 = destFetchProc64[rasterBuffer->format];
@@ -6165,12 +6181,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
quint32 buffer[BufferSize];
const DestFetchProc destFetch = destFetchProc[rasterBuffer->format];
@@ -6243,12 +6255,8 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
colorProfile = QGuiApplicationPrivate::instance()->colorProfileForA32Text();
QRgba64 srcColor = color;
- if (colorProfile) {
- if (color.isOpaque())
- srcColor = colorProfile->toLinear(srcColor);
- else
- srcColor = colorProfile->toLinear(srcColor.unpremultiplied()).premultiplied();
- }
+ if (colorProfile && color.isOpaque())
+ srcColor = colorProfile->toLinear(srcColor);
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
@@ -6774,6 +6782,9 @@ static void qInitDrawhelperFunctions()
qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32_ssse3;
sourceFetchUntransformed[QImage::Format_RGB888] = qt_fetchUntransformed_888_ssse3;
+ extern void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count);
+ qPixelLayouts[QImage::Format_RGB888].rbSwap = rbSwap_888_ssse3;
+ qPixelLayouts[QImage::Format_BGR888].rbSwap = rbSwap_888_ssse3;
}
#endif // SSSE3
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 9c5d525722..dd42b96d79 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -671,6 +671,8 @@ static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src)
static Q_ALWAYS_INLINE void blend_pixel(quint32 &dst, const quint32 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (src != 0) {
const quint32 s = BYTE_MUL(src, const_alpha);
dst = s + BYTE_MUL(dst, qAlpha(~s));
diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp
index 35d61c3e6c..14d7047bb6 100644
--- a/src/gui/painting/qdrawhelper_ssse3.cpp
+++ b/src/gui/painting/qdrawhelper_ssse3.cpp
@@ -40,7 +40,7 @@
#include <private/qdrawhelper_x86_p.h>
-#ifdef QT_COMPILER_SUPPORTS_SSSE3
+#if defined(QT_COMPILER_SUPPORTS_SSSE3)
#include <private/qdrawingprimitive_sse2_p.h>
@@ -254,6 +254,49 @@ void qt_memfill24_ssse3(quint24 *dest, quint24 color, qsizetype count)
}
}
+void QT_FASTCALL rbSwap_888_ssse3(uchar *dst, const uchar *src, int count)
+{
+ int i = 0;
+
+ const static __m128i shuffleMask1 = _mm_setr_epi8(2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, /*!!*/15);
+ const static __m128i shuffleMask2 = _mm_setr_epi8(0, /*!!*/1, 4, 3, 2, 7, 6, 5, 10, 9, 8, 13, 12, 11, /*!!*/14, 15);
+ const static __m128i shuffleMask3 = _mm_setr_epi8(/*!!*/0, 3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, 15, 14, 13);
+
+ for (; i + 15 < count; i += 16) {
+ __m128i s1 = _mm_loadu_si128((const __m128i *)src);
+ __m128i s2 = _mm_loadu_si128((const __m128i *)(src + 16));
+ __m128i s3 = _mm_loadu_si128((const __m128i *)(src + 32));
+ s1 = _mm_shuffle_epi8(s1, shuffleMask1);
+ s2 = _mm_shuffle_epi8(s2, shuffleMask2);
+ s3 = _mm_shuffle_epi8(s3, shuffleMask3);
+ _mm_storeu_si128((__m128i *)dst, s1);
+ _mm_storeu_si128((__m128i *)(dst + 16), s2);
+ _mm_storeu_si128((__m128i *)(dst + 32), s3);
+
+ // Now fix the last four misplaced values
+ std::swap(dst[15], dst[17]);
+ std::swap(dst[30], dst[32]);
+
+ src += 48;
+ dst += 48;
+ }
+
+ if (src != dst) {
+ SIMD_EPILOGUE(i, count, 15) {
+ dst[0] = src[2];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ dst += 3;
+ src += 3;
+ }
+ } else {
+ SIMD_EPILOGUE(i, count, 15) {
+ std::swap(dst[0], dst[2]);
+ dst += 3;
+ }
+ }
+}
+
QT_END_NAMESPACE
#endif // QT_COMPILER_SUPPORTS_SSSE3
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 6cb7b57493..18f212f8e9 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -687,9 +687,6 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
} else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromBt2020()) {
- qCDebug(lcIcc) << "fromIccProfile: BT.2020 primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::Bt2020;
}
if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
@@ -765,10 +762,9 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
qCDebug(lcIcc) << "fromIccProfile: Description" << colorspaceDPtr->description;
}
- if (!colorspaceDPtr->identifyColorSpace())
- colorspaceDPtr->id = QColorSpace::Unknown;
- else
- qCDebug(lcIcc) << "fromIccProfile: Named colorspace detected: " << colorSpace->colorSpaceId();
+ colorspaceDPtr->identifyColorSpace();
+ if (colorspaceDPtr->namedColorSpace)
+ qCDebug(lcIcc) << "fromIccProfile: Named colorspace detected: " << QColorSpace::NamedColorSpace(colorspaceDPtr->namedColorSpace);
colorspaceDPtr->iccProfile = data;
diff --git a/src/gui/painting/qicc_p.h b/src/gui/painting/qicc_p.h
index c3220391f4..2a4658b84b 100644
--- a/src/gui/painting/qicc_p.h
+++ b/src/gui/painting/qicc_p.h
@@ -60,8 +60,8 @@ class QColorSpace;
namespace QIcc {
-Q_GUI_EXPORT bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace);
-Q_GUI_EXPORT QByteArray toIccProfile(const QColorSpace &space);
+bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace);
+QByteArray toIccProfile(const QColorSpace &space);
}
diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp
index a1c9f6e417..c98ca8a1fb 100644
--- a/src/gui/painting/qpagesize.cpp
+++ b/src/gui/painting/qpagesize.cpp
@@ -222,8 +222,6 @@ static const int qt_windowsConversion[][2] = {
{DMPAPER_PENV_10_ROTATED, DMPAPER_PENV_10} // Is = DMPAPER_LAST, use as loop terminator
};
-static const int windowsConversionCount = int(sizeof(qt_windowsConversion) / sizeof(qt_windowsConversion[0]));
-
// Standard sizes data
struct StandardPageSize {
QPageSize::PageSizeId id;
@@ -423,9 +421,9 @@ static QPageSize::PageSizeId qt_idForWindowsID(int windowsId, QSize *match = 0)
if (windowsId <= DMPAPER_NONE || windowsId > DMPAPER_LAST)
return QPageSize::Custom;
// Check if one of the unsupported values, convert to valid value if is
- for (int i = 0; i < windowsConversionCount; ++i) {
- if (qt_windowsConversion[i][0] == windowsId) {
- windowsId = qt_windowsConversion[i][1];
+ for (const auto &it : qt_windowsConversion) {
+ if (it[0] == windowsId) {
+ windowsId = it[1];
break;
}
}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ab5514dd4..8c51981120 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -842,8 +842,8 @@ void QRasterPaintEngine::updateRasterState()
const QPainter::CompositionMode mode = s->composition_mode;
s->flags.fast_text = (s->penData.type == QSpanData::Solid)
&& s->intOpacity == 256
- && (mode == QPainter::CompositionMode_Source
- || (mode == QPainter::CompositionMode_SourceOver
+ && (mode == QPainter::CompositionMode_SourceOver
+ || (mode == QPainter::CompositionMode_Source
&& s->penData.solidColor.isOpaque()));
}
@@ -906,8 +906,11 @@ void QRasterPaintEngine::renderHintsChanged()
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
#if QT_DEPRECATED_SINCE(5, 14)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
if (s->renderHints & QPainter::HighQualityAntialiasing)
s->flags.antialiased = true;
+QT_WARNING_POP
#endif
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
s->flags.legacy_rounding = !bool(s->renderHints & QPainter::Antialiasing) && bool(s->renderHints & QPainter::Qt4CompatiblePainting);
@@ -2214,7 +2217,7 @@ void QRasterPaintEngine::drawImage(const QPointF &p, const QImage &img)
const QClipData *clip = d->clip();
QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
- if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, img.rect())) {
if (!clip) {
d->blitImage(pt, img, d->deviceRect);
return;
@@ -2285,7 +2288,12 @@ namespace {
return NoRotation;
}
- inline bool isPixelAligned(const QRectF &rect) {
+ inline bool isPixelAligned(const QPointF &pt)
+ {
+ return QPointF(pt.toPoint()) == pt;
+ }
+ inline bool isPixelAligned(const QRectF &rect)
+ {
return QRectF(rect.toRect()) == rect;
}
}
@@ -2353,17 +2361,12 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
const QClipData *clip = d->clip();
- if (s->matrix.type() > QTransform::TxTranslate
+ if (s->matrix.type() == QTransform::TxRotate
&& !stretch_sr
&& (!clip || clip->hasRectClip)
&& s->intOpacity == 256
&& (d->rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
- || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)
- && d->rasterBuffer->format == img.format()
- && (d->rasterBuffer->format == QImage::Format_RGB16
- || d->rasterBuffer->format == QImage::Format_RGB32
- || (d->rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
- && d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source)))
+ || d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
{
RotationType rotationType = qRotationType(s->matrix);
const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
@@ -2371,9 +2374,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
QRectF transformedTargetRect = s->matrix.mapRect(r);
- if ((!(s->renderHints & QPainter::SmoothPixmapTransform) && !(s->renderHints & QPainter::Antialiasing))
- || (isPixelAligned(transformedTargetRect) && isPixelAligned(sr)))
- {
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, transformedTargetRect.topRight(), sr)) {
QRect clippedTransformedTargetRect = transformedTargetRect.toRect().intersected(clip ? clip->clipRect : d->deviceRect);
if (clippedTransformedTargetRect.isNull())
return;
@@ -2507,8 +2508,8 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
- if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img)) {
- QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
+ QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
+ if (d->canUseImageBlitting(d->rasterBuffer->compositionMode, img, pt, sr)) {
if (!clip) {
d->blitImage(pt, img, d->deviceRect, sr.toRect());
return;
@@ -2519,7 +2520,6 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
} else if (d->canUseFastImageBlending(d->rasterBuffer->compositionMode, img)) {
SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
if (func) {
- QPointF pt(r.x() + s->matrix.dx(), r.y() + s->matrix.dy());
if (!clip) {
d->drawImage(pt, img, func, d->deviceRect, s->intOpacity, sr.toRect());
return;
@@ -3754,12 +3754,22 @@ bool QRasterPaintEnginePrivate::canUseFastImageBlending(QPainter::CompositionMod
&& !image.hasAlphaChannel()));
}
-bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const
+bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const
{
Q_Q(const QRasterPaintEngine);
+
+ if (!(mode == QPainter::CompositionMode_Source
+ || (mode == QPainter::CompositionMode_SourceOver
+ && !image.hasAlphaChannel())))
+ return false;
+
const QRasterPaintEngineState *s = q->state();
+ Q_ASSERT(s->matrix.type() <= QTransform::TxTranslate || s->matrix.type() == QTransform::TxRotate);
- if (!s->flags.fast_images || s->intOpacity != 256 || qt_depthForFormat(rasterBuffer->format) < 8)
+ if (s->intOpacity != 256
+ || image.depth() < 8
+ || ((s->renderHints & (QPainter::SmoothPixmapTransform | QPainter::Antialiasing))
+ && (!isPixelAligned(pt) || !isPixelAligned(sr))))
return false;
QImage::Format dFormat = rasterBuffer->format;
@@ -3767,18 +3777,13 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo
// Formats must match or source format must be a subset of destination format
if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
- || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888))
+ || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)
+ || (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64))
sFormat = dFormat;
else
sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
}
- if (dFormat != sFormat)
- return false;
-
- return s->matrix.type() <= QTransform::TxTranslate
- && (mode == QPainter::CompositionMode_Source
- || (mode == QPainter::CompositionMode_SourceOver
- && !image.hasAlphaChannel()));
+ return (dFormat == sFormat);
}
QImage QRasterBuffer::colorizeBitmap(const QImage &image, const QColor &color)
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index ec4a35087a..089aadc3f7 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -306,7 +306,7 @@ public:
void recalculateFastImages();
bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const;
- bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image) const;
+ bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const;
QPaintDevice *device;
QScopedPointer<QOutlineMapper> outlineMapper;
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 84b34e390b..3ce54c20be 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1716,8 +1716,8 @@ void QPainter::restore()
static inline void qt_cleanup_painter_state(QPainterPrivate *d)
{
+ qDeleteAll(d->states);
d->states.clear();
- delete d->state;
d->state = 0;
d->engine = 0;
d->device = 0;
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index c71d82546a..45e90bd99b 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -338,7 +338,16 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
}
}
- if (!d_ptr->context->makeCurrent(window)) {
+ bool current = d_ptr->context->makeCurrent(window);
+
+ if (!current && !d_ptr->context->isValid()) {
+ delete d_ptr->blitter;
+ d_ptr->blitter = nullptr;
+ d_ptr->textureId = 0;
+ current = d_ptr->context->create() && d_ptr->context->makeCurrent(window);
+ }
+
+ if (!current) {
qCWarning(lcQpaBackingStore, "composeAndFlush: makeCurrent() failed");
return;
}
@@ -446,14 +455,22 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
d_ptr->blitter->setRedBlueSwizzle(false);
}
- // There is no way to tell if the OpenGL-rendered content is premultiplied or not.
- // For compatibility, assume that it is not, and use normal alpha blend always.
- if (d_ptr->premultiplied)
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
-
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
+ bool blendIsPremultiplied = d_ptr->premultiplied;
for (int i = 0; i < textures->count(); ++i) {
- if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
+ const QPlatformTextureList::Flags flags = textures->flags(i);
+ if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) {
+ if (!blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = true;
+ }
+ } else {
+ if (blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = false;
+ }
+ }
+ if (flags.testFlag(QPlatformTextureList::StacksOnTop))
blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
}
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index 414d2bf0de..4f08b0092f 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -81,7 +81,8 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject
public:
enum Flag {
StacksOnTop = 0x01,
- TextureIsSrgb = 0x02
+ TextureIsSrgb = 0x02,
+ NeedsPremultipliedAlphaBlending = 0x04
};
Q_DECLARE_FLAGS(Flags, Flag)
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 51eed962f0..82f5be2b65 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -88,60 +88,6 @@ QT_BEGIN_NAMESPACE
Example of using complex regions:
\snippet code/src_gui_painting_qregion.cpp 0
- \section1 Additional License Information
-
- On Embedded Linux and X11 platforms, parts of this class rely on
- code obtained under the following licenses:
-
- \legalese
- Copyright (c) 1987 X Consortium
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Except as contained in this notice, the name of the X Consortium shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from the X Consortium.
- \endlegalese
-
- \br
-
- \legalese
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Digital not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
-
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
- ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- SOFTWARE.
- \endlegalese
-
\sa QPainter::setClipRegion(), QPainter::setClipRect(), QPainterPath
*/
diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h
index ca879de27c..d145dbfbea 100644
--- a/src/gui/painting/qrgba64_p.h
+++ b/src/gui/painting/qrgba64_p.h
@@ -284,6 +284,8 @@ static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src)
static Q_ALWAYS_INLINE void blend_pixel(QRgba64 &dst, QRgba64 src, const int const_alpha)
{
+ if (const_alpha == 255)
+ return blend_pixel(dst, src);
if (!src.isTransparent()) {
src = multiplyAlpha255(src, const_alpha);
dst = src + multiplyAlpha65535(dst, 65535 - src.alpha());
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index 9d3debc1b9..7b16e8c211 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -41,5 +41,20 @@
"LicenseId": "MIT",
"LicenseFile": "WEBGRADIENTS_LICENSE.txt",
"Copyright": "Copyright (c) 2017 itmeo"
+ },
+ {
+ "Id": "xserverhelper",
+ "Name": "X Server helper",
+ "QDocModule": "qtgui",
+ "QtUsage": "Used in Qt GUI (QRegion).",
+ "Files": "qregion.cpp",
+
+ "Description": "Code from X11's region.h, Region.c, poly.h, and PolyReg.c",
+ "Homepage": "https://www.x.org/",
+ "License": "X11 License and Historical Permission Notice and Disclaimer",
+ "LicenseId": "X11 AND HPND",
+ "LicenseFile": "XCONSORTIUM_LICENSE.txt",
+ "Copyright": "Copyright (c) 1987, 1988 X Consortium
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."
}
]
diff --git a/src/gui/rhi/cs_tdr_p.h b/src/gui/rhi/cs_tdr_p.h
new file mode 100644
index 0000000000..620a4a101d
--- /dev/null
+++ b/src/gui/rhi/cs_tdr_p.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Gui module
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CS_TDR_P_H
+#define CS_TDR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifdef Q_OS_WIN
+
+#include <qt_windows.h>
+
+#if 0
+//
+// Generated by Microsoft (R) HLSL Shader Compiler 10.1
+//
+//
+// Buffer Definitions:
+//
+// cbuffer ConstantBuffer
+// {
+//
+// uint zero; // Offset: 0 Size: 4
+//
+// }
+//
+//
+// Resource Bindings:
+//
+// Name Type Format Dim HLSL Bind Count
+// ------------------------------ ---------- ------- ----------- -------------- ------
+// uav UAV uint buf u0 1
+// ConstantBuffer cbuffer NA NA cb0 1
+//
+//
+//
+// Input signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Input
+//
+// Output signature:
+//
+// Name Index Mask Register SysValue Format Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// no Output
+cs_5_0
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[1], immediateIndexed
+dcl_uav_typed_buffer (uint,uint,uint,uint) u0
+dcl_input vThreadID.x
+dcl_thread_group 256, 1, 1
+loop
+ breakc_nz cb0[0].x
+ store_uav_typed u0.xyzw, vThreadID.xxxx, cb0[0].xxxx
+endloop
+ret
+// Approximately 5 instruction slots used
+#endif
+
+const BYTE g_killDeviceByTimingOut[] =
+{
+ 68, 88, 66, 67, 217, 62,
+ 220, 38, 136, 51, 86, 245,
+ 161, 96, 18, 35, 141, 17,
+ 26, 13, 1, 0, 0, 0,
+ 164, 2, 0, 0, 5, 0,
+ 0, 0, 52, 0, 0, 0,
+ 100, 1, 0, 0, 116, 1,
+ 0, 0, 132, 1, 0, 0,
+ 8, 2, 0, 0, 82, 68,
+ 69, 70, 40, 1, 0, 0,
+ 1, 0, 0, 0, 144, 0,
+ 0, 0, 2, 0, 0, 0,
+ 60, 0, 0, 0, 0, 5,
+ 83, 67, 0, 1, 0, 0,
+ 0, 1, 0, 0, 82, 68,
+ 49, 49, 60, 0, 0, 0,
+ 24, 0, 0, 0, 32, 0,
+ 0, 0, 40, 0, 0, 0,
+ 36, 0, 0, 0, 12, 0,
+ 0, 0, 0, 0, 0, 0,
+ 124, 0, 0, 0, 4, 0,
+ 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 255, 255,
+ 255, 255, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 128, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 117, 97,
+ 118, 0, 67, 111, 110, 115,
+ 116, 97, 110, 116, 66, 117,
+ 102, 102, 101, 114, 0, 171,
+ 128, 0, 0, 0, 1, 0,
+ 0, 0, 168, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 208, 0, 0, 0, 0, 0,
+ 0, 0, 4, 0, 0, 0,
+ 2, 0, 0, 0, 220, 0,
+ 0, 0, 0, 0, 0, 0,
+ 255, 255, 255, 255, 0, 0,
+ 0, 0, 255, 255, 255, 255,
+ 0, 0, 0, 0, 122, 101,
+ 114, 111, 0, 100, 119, 111,
+ 114, 100, 0, 171, 0, 0,
+ 19, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 213, 0, 0, 0, 77, 105,
+ 99, 114, 111, 115, 111, 102,
+ 116, 32, 40, 82, 41, 32,
+ 72, 76, 83, 76, 32, 83,
+ 104, 97, 100, 101, 114, 32,
+ 67, 111, 109, 112, 105, 108,
+ 101, 114, 32, 49, 48, 46,
+ 49, 0, 73, 83, 71, 78,
+ 8, 0, 0, 0, 0, 0,
+ 0, 0, 8, 0, 0, 0,
+ 79, 83, 71, 78, 8, 0,
+ 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 83, 72,
+ 69, 88, 124, 0, 0, 0,
+ 80, 0, 5, 0, 31, 0,
+ 0, 0, 106, 8, 0, 1,
+ 89, 0, 0, 4, 70, 142,
+ 32, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 156, 8,
+ 0, 4, 0, 224, 17, 0,
+ 0, 0, 0, 0, 68, 68,
+ 0, 0, 95, 0, 0, 2,
+ 18, 0, 2, 0, 155, 0,
+ 0, 4, 0, 1, 0, 0,
+ 1, 0, 0, 0, 1, 0,
+ 0, 0, 48, 0, 0, 1,
+ 3, 0, 4, 4, 10, 128,
+ 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 164, 0,
+ 0, 7, 242, 224, 17, 0,
+ 0, 0, 0, 0, 6, 0,
+ 2, 0, 6, 128, 32, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 22, 0, 0, 1,
+ 62, 0, 0, 1, 83, 84,
+ 65, 84, 148, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0
+};
+
+#endif // Q_OS_WIN
+
+#endif // CS_TDR_P_H
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 4414b61d55..dabad35688 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -439,6 +439,18 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
visible in external GPU debugging tools will not be available and functions
like QRhiCommandBuffer::debugMarkBegin() will become a no-op. Avoid
enabling in production builds as it may involve a performance penalty.
+
+ \value PreferSoftwareRenderer Indicates that backends should prefer
+ choosing an adapter or physical device that renders in software on the CPU.
+ For example, with Direct3D there is typically a "Basic Render Driver"
+ adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag
+ requests the backend to choose that adapter over any other, as long as no
+ specific adapter was forced by other backend-specific means. With Vulkan
+ this maps to preferring physical devices with
+ \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not
+ possible to decide if an adapter/device is software-based, this flag is
+ ignored. It may also be ignored with graphics APIs that have no concept and
+ means of enumerating adapters/devices.
*/
/*!
@@ -455,8 +467,8 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\value FrameOpDeviceLost The graphics device was lost. This can be
recoverable by attempting to repeat the operation (such as, beginFrame())
- and releasing and reinitializing all objects backed by native graphics
- resources.
+ after releasing and reinitializing all objects backed by native graphics
+ resources. See isDeviceLost().
*/
/*!
@@ -551,6 +563,21 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\value BaseInstance Indicates that instanced draw commands support the \c
firstInstance argument. When reported as not supported, the firstInstance
value is ignored and the instance ID starts from 0.
+
+ \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
+ supports QRhiGraphicsPipeline::TriangleFan.
+
+ \value ReadBackNonUniformBuffer Indicates that
+ \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is
+ supported for QRhiBuffer instances with a usage different than
+ UniformBuffer. While this is supported in the majority of cases, it will be
+ unsupported with OpenGL ES older than 3.0.
+
+ \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other
+ than 0 is supported when reading back texture contents. When not supported,
+ specifying a non-zero level in QRhiReadbackDescription leads to returning
+ an all-zero image. In practice this feature will be unsupported with OpenGL
+ ES 2.0, while it will likely be supported everywhere else.
*/
/*!
@@ -673,7 +700,7 @@ bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClear
*/
uint qHash(const QRhiDepthStencilClearValue &v, uint seed) Q_DECL_NOTHROW
{
- return seed * (qFloor(v.depthClearValue() * 100) + v.stencilClearValue());
+ return seed * (uint(qFloor(qreal(v.depthClearValue()) * 100)) + v.stencilClearValue());
}
#ifndef QT_NO_DEBUG_STREAM
@@ -695,8 +722,8 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
Used with QRhiCommandBuffer::setViewport().
- \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
- bottom-left.
+ QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
+ bottom-left. Negative width or height are not allowed.
Typical usage is like the following:
@@ -725,7 +752,9 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
Constructs a viewport description with the rectangle specified by \a x, \a
y, \a w, \a h and the depth range \a minDepth and \a maxDepth.
- \note x and y are assumed to be the bottom-left position.
+ \note \a x and \a y are assumed to be the bottom-left position. \a w and \a
+ h should not be negative, the viewport will be ignored by
+ QRhiCommandBuffer::setViewport() otherwise.
\sa QRhi::clipSpaceCorrMatrix()
*/
@@ -768,7 +797,8 @@ bool operator!=(const QRhiViewport &a, const QRhiViewport &b) Q_DECL_NOTHROW
uint qHash(const QRhiViewport &v, uint seed) Q_DECL_NOTHROW
{
const std::array<float, 4> r = v.viewport();
- return seed + r[0] + r[1] + r[2] + r[3] + qFloor(v.minDepth() * 100) + qFloor(v.maxDepth() * 100);
+ return seed + uint(r[0]) + uint(r[1]) + uint(r[2]) + uint(r[3])
+ + uint(qFloor(qreal(v.minDepth()) * 100)) + uint(qFloor(qreal(v.maxDepth()) * 100));
}
#ifndef QT_NO_DEBUG_STREAM
@@ -797,8 +827,12 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
only possible with a QRhiGraphicsPipeline that has
QRhiGraphicsPipeline::UsesScissor set.
- \note QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
- bottom-left.
+ QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
+ bottom-left. Negative width or height are not allowed. However, apart from
+ that, the flexible OpenGL semantics apply: negative x and y, partially out
+ of bounds rectangles, etc. will be handled gracefully, clamping as
+ appropriate. Therefore, any rendering logic targeting OpenGL can feed
+ scissor rectangles into QRhiScissor as-is, without any adaptation.
\sa QRhiCommandBuffer::setScissor(), QRhiViewport
*/
@@ -813,7 +847,11 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and
\a h.
- \note x and y are assumed to be the bottom-left position.
+ \note \a x and \a y are assumed to be the bottom-left position. Negative \a w
+ or \a h are not allowed, such scissor rectangles will be ignored by
+ QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply:
+ negative x and y, partially out of bounds rectangles, etc. will be handled
+ gracefully, clamping as appropriate.
*/
QRhiScissor::QRhiScissor(int x, int y, int w, int h)
: m_rect { { x, y, w, h } }
@@ -850,7 +888,7 @@ bool operator!=(const QRhiScissor &a, const QRhiScissor &b) Q_DECL_NOTHROW
uint qHash(const QRhiScissor &v, uint seed) Q_DECL_NOTHROW
{
const std::array<int, 4> r = v.scissor();
- return seed + r[0] + r[1] + r[2] + r[3];
+ return seed + uint(r[0]) + uint(r[1]) + uint(r[2]) + uint(r[3]);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -1136,7 +1174,7 @@ bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribut
*/
uint qHash(const QRhiVertexInputAttribute &v, uint seed) Q_DECL_NOTHROW
{
- return seed + v.binding() + v.location() + v.format() + v.offset();
+ return seed + uint(v.binding()) + uint(v.location()) + uint(v.format()) + v.offset();
}
#ifndef QT_NO_DEBUG_STREAM
@@ -1176,8 +1214,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a)
*/
bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW
{
- return a.bindings() == b.bindings()
- && a.attributes() == b.attributes();
+ return a.m_bindings == b.m_bindings && a.m_attributes == b.m_attributes;
}
/*!
@@ -1198,15 +1235,21 @@ bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b)
*/
uint qHash(const QRhiVertexInputLayout &v, uint seed) Q_DECL_NOTHROW
{
- return qHash(v.bindings(), seed) + qHash(v.attributes(), seed);
+ return qHash(v.m_bindings, seed) + qHash(v.m_attributes, seed);
}
#ifndef QT_NO_DEBUG_STREAM
+template<typename T, int N>
+QDebug operator<<(QDebug dbg, const QVarLengthArray<T, N> &vla)
+{
+ return QtPrivate::printSequentialContainer(dbg, "VLA", vla);
+}
+
QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
{
QDebugStateSaver saver(dbg);
- dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.bindings()
- << " attributes=" << v.attributes()
+ dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings
+ << " attributes=" << v.m_attributes
<< ')';
return dbg;
}
@@ -1607,28 +1650,20 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUplo
}
/*!
- Constructs a texture upload description with the specified list of \a entries.
+ Constructs a texture upload description with the specified \a list of entries.
- \note \a entries can also contain multiple QRhiTextureUploadEntry elements
+ \note \a list can also contain multiple QRhiTextureUploadEntry elements
with the the same layer and level. This makes sense when those uploads are
partial, meaning their subresource description has a source size or image
smaller than the subresource dimensions, and can be more efficient than
issuing separate uploadTexture()'s.
*/
-QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QVector<QRhiTextureUploadEntry> &entries)
- : m_entries(entries)
+QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list)
+ : m_entries(list)
{
}
/*!
- Adds \a entry to the list of subresource uploads.
- */
-void QRhiTextureUploadDescription::append(const QRhiTextureUploadEntry &entry)
-{
- m_entries.append(entry);
-}
-
-/*!
\class QRhiTextureCopyDescription
\internal
\inmodule QtGui
@@ -1958,6 +1993,14 @@ QRhiResource::Type QRhiBuffer::resourceType() const
How the renderbuffer is implemented by a backend is not exposed to the
applications. In some cases it may be backed by ordinary textures, while in
others there may be a different kind of native resource used.
+
+ Renderbuffers that are used as (and are only used as) depth-stencil buffers
+ in combination with a QRhiSwapChain's color buffers should have the
+ UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
+ depending on the backend and the underlying APIs, be more efficient, and
+ QRhi provides automatic sizing behavior to match the color buffers, which
+ means calling setPixelSize() and build() are not necessary for such
+ renderbuffers.
*/
/*!
@@ -1973,12 +2016,15 @@ QRhiResource::Type QRhiBuffer::resourceType() const
Flag values for flags() and setFlags()
\value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
- that the renderbuffer is only used in combination with a QRhiSwapChain and
- never in other ways. Relevant with some backends, while others ignore it.
- With OpenGL where a separate windowing system interface API is in use (EGL,
- GLX, etc.), the flag is important since it avoids creating any actual
- resource as there is already a windowing system provided depth/stencil
- buffer as requested by QSurfaceFormat.
+ that the renderbuffer is only used in combination with a QRhiSwapChain, and
+ never in any other way. This provides automatic sizing and resource
+ rebuilding, so calling setPixelSize() or build() is not needed whenever
+ this flag is set. This flag value may also trigger backend-specific
+ behavior, for example with OpenGL, where a separate windowing system
+ interface API is in use (EGL, GLX, etc.), the flag is especially important
+ as it avoids creating any actual renderbuffer resource as there is already
+ a windowing system provided depth/stencil buffer as requested by
+ QSurfaceFormat.
*/
/*!
@@ -2500,16 +2546,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
be used with the same pipeline, assuming the pipeline was built with one of
them in the first place.
- Creating and then using a new \c srb2 that is very similar to \c srb with
- the exception of referencing another texture could be implemented like the
- following:
-
\badcode
srb2 = rhi->newShaderResourceBindings();
- QVector<QRhiShaderResourceBinding> bindings = srb->bindings();
- bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler);
- srb2->setBindings(bindings);
- srb2->build();
...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(srb2); // binds srb2
@@ -2611,43 +2649,10 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
- : d(new QRhiShaderResourceBindingPrivate)
-{
-}
-
-/*!
- \internal
- */
-void QRhiShaderResourceBinding::detach()
{
- qAtomicDetach(d);
-}
-
-/*!
- \internal
- */
-QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other)
- : d(other.d)
-{
- d->ref.ref();
-}
-
-/*!
- \internal
- */
-QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other)
-{
- qAtomicAssign(d, other.d);
- return *this;
-}
-
-/*!
- Destructor.
- */
-QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
-{
- if (!d->ref.deref())
- delete d;
+ // Zero out everything, including possible padding, because will use
+ // qHashBits on it.
+ memset(&d.u, 0, sizeof(d.u));
}
/*!
@@ -2664,8 +2669,7 @@ QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
*/
bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
{
- return (d == other.d)
- || (d->binding == other.d->binding && d->stage == other.d->stage && d->type == other.d->type);
+ return d.binding == other.d.binding && d.stage == other.d.stage && d.type == other.d.type;
}
/*!
@@ -2678,15 +2682,13 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.loadRelaxed() == 1);
- d->binding = binding;
- d->stage = stage;
- d->type = UniformBuffer;
- d->u.ubuf.buf = buf;
- d->u.ubuf.offset = 0;
- d->u.ubuf.maybeSize = 0; // entire buffer
- d->u.ubuf.hasDynamicOffset = false;
+ b.d.binding = binding;
+ b.d.stage = stage;
+ b.d.type = UniformBuffer;
+ b.d.u.ubuf.buf = buf;
+ b.d.u.ubuf.offset = 0;
+ b.d.u.ubuf.maybeSize = 0; // entire buffer
+ b.d.u.ubuf.hasDynamicOffset = false;
return b;
}
@@ -2707,9 +2709,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->u.ubuf.offset = offset;
- d->u.ubuf.maybeSize = size;
+ b.d.u.ubuf.offset = offset;
+ b.d.u.ubuf.maybeSize = size;
return b;
}
@@ -2728,8 +2729,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
int binding, StageFlags stage, QRhiBuffer *buf, int size)
{
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->u.ubuf.hasDynamicOffset = true;
+ b.d.u.ubuf.hasDynamicOffset = true;
return b;
}
@@ -2742,13 +2742,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
{
QRhiShaderResourceBinding b;
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.loadRelaxed() == 1);
- d->binding = binding;
- d->stage = stage;
- d->type = SampledTexture;
- d->u.stex.tex = tex;
- d->u.stex.sampler = sampler;
+ b.d.binding = binding;
+ b.d.stage = stage;
+ b.d.type = SampledTexture;
+ b.d.u.stex.tex = tex;
+ b.d.u.stex.sampler = sampler;
return b;
}
@@ -2764,13 +2762,11 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b;
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.loadRelaxed() == 1);
- d->binding = binding;
- d->stage = stage;
- d->type = ImageLoad;
- d->u.simage.tex = tex;
- d->u.simage.level = level;
+ b.d.binding = binding;
+ b.d.stage = stage;
+ b.d.type = ImageLoad;
+ b.d.u.simage.tex = tex;
+ b.d.u.simage.level = level;
return b;
}
@@ -2786,8 +2782,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->type = ImageStore;
+ b.d.type = ImageStore;
return b;
}
@@ -2803,8 +2798,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
int binding, StageFlags stage, QRhiTexture *tex, int level)
{
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->type = ImageLoadStore;
+ b.d.type = ImageLoadStore;
return b;
}
@@ -2818,14 +2812,12 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- Q_ASSERT(d->ref.loadRelaxed() == 1);
- d->binding = binding;
- d->stage = stage;
- d->type = BufferLoad;
- d->u.sbuf.buf = buf;
- d->u.sbuf.offset = 0;
- d->u.sbuf.maybeSize = 0; // entire buffer
+ b.d.binding = binding;
+ b.d.stage = stage;
+ b.d.type = BufferLoad;
+ b.d.u.sbuf.buf = buf;
+ b.d.u.sbuf.offset = 0;
+ b.d.u.sbuf.maybeSize = 0; // entire buffer
return b;
}
@@ -2841,9 +2833,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->u.sbuf.offset = offset;
- d->u.sbuf.maybeSize = size;
+ b.d.u.sbuf.offset = offset;
+ b.d.u.sbuf.maybeSize = size;
return b;
}
@@ -2857,8 +2848,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->type = BufferStore;
+ b.d.type = BufferStore;
return b;
}
@@ -2874,9 +2864,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->u.sbuf.offset = offset;
- d->u.sbuf.maybeSize = size;
+ b.d.u.sbuf.offset = offset;
+ b.d.u.sbuf.maybeSize = size;
return b;
}
@@ -2890,8 +2879,7 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->type = BufferLoadStore;
+ b.d.type = BufferLoadStore;
return b;
}
@@ -2907,9 +2895,8 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
{
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
- QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
- d->u.sbuf.offset = offset;
- d->u.sbuf.maybeSize = size;
+ b.d.u.sbuf.offset = offset;
+ b.d.u.sbuf.maybeSize = size;
return b;
}
@@ -2925,28 +2912,32 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
*/
bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW
{
- if (a.d == b.d)
+ const QRhiShaderResourceBinding::Data *da = a.data();
+ const QRhiShaderResourceBinding::Data *db = b.data();
+
+ if (da == db)
return true;
- if (a.d->binding != b.d->binding
- || a.d->stage != b.d->stage
- || a.d->type != b.d->type)
+
+ if (da->binding != db->binding
+ || da->stage != db->stage
+ || da->type != db->type)
{
return false;
}
- switch (a.d->type) {
+ switch (da->type) {
case QRhiShaderResourceBinding::UniformBuffer:
- if (a.d->u.ubuf.buf != b.d->u.ubuf.buf
- || a.d->u.ubuf.offset != b.d->u.ubuf.offset
- || a.d->u.ubuf.maybeSize != b.d->u.ubuf.maybeSize)
+ if (da->u.ubuf.buf != db->u.ubuf.buf
+ || da->u.ubuf.offset != db->u.ubuf.offset
+ || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
{
return false;
}
break;
case QRhiShaderResourceBinding::SampledTexture:
- if (a.d->u.stex.tex != b.d->u.stex.tex
- || a.d->u.stex.sampler != b.d->u.stex.sampler)
+ if (da->u.stex.tex != db->u.stex.tex
+ || da->u.stex.sampler != db->u.stex.sampler)
{
return false;
}
@@ -2956,8 +2947,8 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::ImageStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
- if (a.d->u.simage.tex != b.d->u.simage.tex
- || a.d->u.simage.level != b.d->u.simage.level)
+ if (da->u.simage.tex != db->u.simage.tex
+ || da->u.simage.level != db->u.simage.level)
{
return false;
}
@@ -2967,9 +2958,9 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
case QRhiShaderResourceBinding::BufferStore:
Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
- if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
- || a.d->u.sbuf.offset != b.d->u.sbuf.offset
- || a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
+ if (da->u.sbuf.buf != db->u.sbuf.buf
+ || da->u.sbuf.offset != db->u.sbuf.offset
+ || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
{
return false;
}
@@ -3000,16 +2991,16 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
*/
uint qHash(const QRhiShaderResourceBinding &b, uint seed) Q_DECL_NOTHROW
{
- const char *u = reinterpret_cast<const char *>(&b.d->u);
- return seed + b.d->binding + 10 * b.d->stage + 100 * b.d->type
- + qHash(QByteArray::fromRawData(u, sizeof(b.d->u)), seed);
+ const QRhiShaderResourceBinding::Data *d = b.data();
+ return seed + uint(d->binding) + 10 * uint(d->stage) + 100 * uint(d->type)
+ + qHashBits(&d->u, sizeof(d->u), seed);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
{
- const QRhiShaderResourceBindingPrivate *d = b.d;
QDebugStateSaver saver(dbg);
+ const QRhiShaderResourceBinding::Data *d = b.data();
dbg.nospace() << "QRhiShaderResourceBinding("
<< "binding=" << d->binding
<< " stage=" << d->stage
@@ -3093,9 +3084,13 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
\inmodule QtGui
\brief Graphics pipeline state resource.
+ \note Setting the shader stages is mandatory. There must be at least one
+ stage, and there must be a vertex stage.
+
\note Setting the shader resource bindings is mandatory. The referenced
QRhiShaderResourceBindings must already be built by the time build() is
- called.
+ called. Associating with a QRhiShaderResourceBindings that has no bindings
+ is also valid, as long as no shader in any stage expects any resources.
\note Setting the render pass descriptor is mandatory. To obtain a
QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
@@ -3104,8 +3099,6 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
\note Setting the vertex input layout is mandatory.
- \note Setting the shader stages is mandatory.
-
\note sampleCount() defaults to 1 and must match the sample count of the
render target's color and depth stencil attachments.
@@ -3147,6 +3140,7 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
\value Triangles (default)
\value TriangleStrip
+ \value TriangleFan (only available if QRhi::TriangleFanTopology is supported)
\value Lines
\value LineStrip
\value Points
@@ -3328,7 +3322,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
{
sc = rhi->newSwapChain();
ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
- QSize(), // no need to set the size yet
+ QSize(), // no need to set the size here due to UsedWithSwapChainOnly
1,
QRhiRenderBuffer::UsedWithSwapChainOnly);
sc->setWindow(window);
@@ -3340,9 +3334,6 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
void resizeSwapChain()
{
- const QSize outputSize = sc->surfacePixelSize();
- ds->setPixelSize(outputSize);
- ds->build();
hasSwapChain = sc->buildOrResize();
}
@@ -3457,10 +3448,18 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
Flag values to describe swapchain properties
\value SurfaceHasPreMulAlpha Indicates that the target surface has
- transparency with premultiplied alpha.
+ transparency with premultiplied alpha. For example, this is what Qt Quick
+ uses when the alpha channel is enabled on the target QWindow, because the
+ scenegraph rendrerer always outputs fragments with alpha multiplied into
+ the red, green, and blue values. To ensure identical behavior across
+ platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value
+ on the target QWindow whenever this flag is set on the swapchain.
\value SurfaceHasNonPreMulAlpha Indicates the target surface has
- transparencyt with non-premultiplied alpha.
+ transparency with non-premultiplied alpha. Be aware that this may not be
+ supported on some systems, if the system compositor always expects content
+ with premultiplied alpha. In that case the behavior with this flag set is
+ expected to be equivalent to SurfaceHasPreMulAlpha.
\value sRGB Requests to pick an sRGB format for the swapchain and/or its
render target views, where applicable. Note that this implies that sRGB
@@ -3528,10 +3527,24 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
\return The size of the window's associated surface or layer. Do not assume
this is the same as QWindow::size() * QWindow::devicePixelRatio().
- Can be called before buildOrResize() (but with window() already set), which
- allows setting the correct size for the depth-stencil buffer that is then
- used together with the swapchain's color buffers. Also used in combination
- with currentPixelSize() to detect size changes.
+ \note Can also be called before buildOrResize(), if at least window() is
+ already set) This in combination with currentPixelSize() allows to detect
+ when a swapchain needs to be resized. However, watch out for the fact that
+ the size of the underlying native object (surface, layer, or similar) is
+ "live", so whenever this function is called, it returns the latest value
+ reported by the underlying implementation, without any atomicity guarantee.
+ Therefore, using this function to determine pixel sizes for graphics
+ resources that are used in a frame is strongly discouraged. Rely on
+ currentPixelSize() instead which returns a size that is atomic and will not
+ change between buildOrResize() invocations.
+
+ \note For depth-stencil buffers used in combination with the swapchain's
+ color buffers, it is strongly recommended to rely on the automatic sizing
+ and rebuilding behavior provided by the
+ QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
+ size via this function just to get a size that can be passed to
+ QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
+ atomicity as described above.
\sa currentPixelSize()
*/
@@ -3823,8 +3836,8 @@ void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const
break;
}
- const quint32 wblocks = (size.width() + xdim - 1) / xdim;
- const quint32 hblocks = (size.height() + ydim - 1) / ydim;
+ const quint32 wblocks = uint((size.width() + xdim - 1) / xdim);
+ const quint32 hblocks = uint((size.height() + ydim - 1) / ydim);
if (bpl)
*bpl = wblocks * blockSize;
@@ -3880,9 +3893,9 @@ void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSi
}
if (bpl)
- *bpl = size.width() * bpc;
+ *bpl = uint(size.width()) * bpc;
if (byteSize)
- *byteSize = size.width() * size.height() * bpc;
+ *byteSize = uint(size.width() * size.height()) * bpc;
}
// Approximate because it excludes subresource alignment or multisampling.
@@ -3892,15 +3905,55 @@ quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format,
quint32 approxSize = 0;
for (int level = 0; level < mipCount; ++level) {
quint32 byteSize = 0;
- const QSize size(qFloor(float(qMax(1, baseSize.width() >> level))),
- qFloor(float(qMax(1, baseSize.height() >> level))));
+ const QSize size(qFloor(qreal(qMax(1, baseSize.width() >> level))),
+ qFloor(qreal(qMax(1, baseSize.height() >> level))));
textureFormatInfo(format, size, nullptr, &byteSize);
approxSize += byteSize;
}
- approxSize *= layerCount;
+ approxSize *= uint(layerCount);
return approxSize;
}
+bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
+{
+ if (ps->cbeginShaderStages() == ps->cendShaderStages()) {
+ qWarning("Cannot build a graphics pipeline without any stages");
+ return false;
+ }
+
+ bool hasVertexStage = false;
+ for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) {
+ if (!it->shader().isValid()) {
+ qWarning("Empty shader passed to graphics pipeline");
+ return false;
+ }
+ if (it->type() == QRhiShaderStage::Vertex) {
+ hasVertexStage = true;
+ const QRhiVertexInputLayout inputLayout = ps->vertexInputLayout();
+ if (inputLayout.cbeginAttributes() == inputLayout.cendAttributes()) {
+ qWarning("Vertex stage present without any vertex inputs");
+ return false;
+ }
+ }
+ }
+ if (!hasVertexStage) {
+ qWarning("Cannot build a graphics pipeline without a vertex stage");
+ return false;
+ }
+
+ if (!ps->renderPassDescriptor()) {
+ qWarning("Cannot build a graphics pipeline without a QRhiRenderPassDescriptor");
+ return false;
+ }
+
+ if (!ps->shaderResourceBindings()) {
+ qWarning("Cannot build a graphics pipeline without QRhiShaderResourceBindings");
+ return false;
+ }
+
+ return true;
+}
+
/*!
\internal
*/
@@ -4176,7 +4229,7 @@ void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other)
void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
{
if (size > 0)
- d->dynamicBufferUpdates.append({ buf, offset, size, data });
+ d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
}
/*!
@@ -4190,7 +4243,7 @@ void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, i
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
{
if (size > 0)
- d->staticBufferUploads.append({ buf, offset, size, data });
+ d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
}
/*!
@@ -4200,7 +4253,28 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, in
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
{
if (buf->size() > 0)
- d->staticBufferUploads.append({ buf, 0, 0, data });
+ d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data));
+}
+
+/*!
+ Enqueues reading back a region of the QRhiBuffer \a buf. The size of the
+ region is specified by \a size in bytes, \a offset is the offset in bytes
+ to start reading from.
+
+ A readback is asynchronous. \a result contains a callback that is invoked
+ when the operation has completed. The data is provided in
+ QRhiBufferReadbackResult::data. Upon successful completion that QByteArray
+ will have a size equal to \a size. On failure the QByteArray will be empty.
+
+ \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer
+ is supported only when the QRhi::ReadBackNonUniformBuffer feature is
+ reported as supported.
+
+ \a readBackTexture(), QRhi::isFeatureSupported()
+ */
+void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
+{
+ d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
}
/*!
@@ -4212,8 +4286,8 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da
*/
void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
{
- if (!desc.entries().isEmpty())
- d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureUpload(tex, desc));
+ if (desc.cbeginEntries() != desc.cendEntries())
+ d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
}
/*!
@@ -4238,7 +4312,7 @@ void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &imag
*/
void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
{
- d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureCopy(dst, src, desc));
+ d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
}
/*!
@@ -4290,7 +4364,7 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co
*/
void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
- d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureRead(rb, result));
+ d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
}
/*!
@@ -4302,7 +4376,7 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb,
*/
void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex, int layer)
{
- d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureMipGen(tex, layer));
+ d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer));
}
/*!
@@ -4351,8 +4425,7 @@ void QRhiResourceUpdateBatchPrivate::free()
{
Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
- dynamicBufferUpdates.clear();
- staticBufferUploads.clear();
+ bufferOps.clear();
textureOps.clear();
rhi->resUpdPoolMap.clearBit(poolIndex);
@@ -4361,9 +4434,13 @@ void QRhiResourceUpdateBatchPrivate::free()
void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
{
- dynamicBufferUpdates += other->dynamicBufferUpdates;
- staticBufferUploads += other->staticBufferUploads;
- textureOps += other->textureOps;
+ bufferOps.reserve(bufferOps.size() + other->bufferOps.size());
+ for (const BufferOp &op : qAsConst(other->bufferOps))
+ bufferOps.append(op);
+
+ textureOps.reserve(textureOps.size() + other->textureOps.size());
+ for (const TextureOp &op : qAsConst(other->textureOps))
+ textureOps.append(op);
}
/*!
@@ -5001,10 +5078,17 @@ const QRhiNativeHandles *QRhi::nativeHandles()
has to ensure external OpenGL code provided by the application can still
run like it did before with direct usage of OpenGL, as long as the QRhi is
using the OpenGL backend.
+
+ \return false when failed, similarly to QOpenGLContext::makeCurrent(). When
+ the operation failed, isDeviceLost() can be called to determine if there
+ was a loss of context situation. Such a check is equivalent to checking via
+ QOpenGLContext::isValid().
+
+ \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid()
*/
-void QRhi::makeThreadLocalNativeContextCurrent()
+bool QRhi::makeThreadLocalNativeContextCurrent()
{
- d->makeThreadLocalNativeContextCurrent();
+ return d->makeThreadLocalNativeContextCurrent();
}
/*!
@@ -5020,6 +5104,70 @@ QRhiProfiler *QRhi::profiler()
}
/*!
+ Attempts to release resources in the backend's caches. This can include both
+ CPU and GPU resources. Only memory and resources that can be recreated
+ automatically are in scope. As an example, if the backend's
+ QRhiGraphicsPipeline implementation maintains a cache of shader compilation
+ results, calling this function leads to emptying that cache, thus
+ potentially freeing up memory and graphics resources.
+
+ Calling this function makes sense in resource constrained environments,
+ where at a certain point there is a need to ensure minimal resource usage,
+ at the expense of performance.
+ */
+void QRhi::releaseCachedResources()
+{
+ d->releaseCachedResources();
+}
+
+/*!
+ \return true if the graphics device was lost.
+
+ The loss of the device is typically detected in beginFrame(), endFrame() or
+ QRhiSwapChain::buildOrResize(), depending on the backend and the underlying
+ native APIs. The most common is endFrame() because that is where presenting
+ happens. With some backends QRhiSwapChain::buildOrResize() can also fail
+ due to a device loss. Therefore this function is provided as a generic way
+ to check if a device loss was detected by a previous operation.
+
+ When the device is lost, no further operations should be done via the QRhi.
+ Rather, all QRhi resources should be released, followed by destroying the
+ QRhi. A new QRhi can then be attempted to be created. If successful, all
+ graphics resources must be reinitialized. If not, try again later,
+ repeatedly.
+
+ While simple applications may decide to not care about device loss,
+ on the commonly used desktop platforms a device loss can happen
+ due to a variety of reasons, including physically disconnecting the
+ graphics adapter, disabling the device or driver, uninstalling or upgrading
+ the graphics driver, or due to errors that lead to a graphics device reset.
+ Some of these can happen under perfectly normal circumstances as well, for
+ example the upgrade of the graphics driver to a newer version is a common
+ task that can happen at any time while a Qt application is running. Users
+ may very well expect applications to be able to survive this, even when the
+ application is actively using an API like OpenGL or Direct3D.
+
+ Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be
+ expected to handle and take appropriate measures when a device loss occurs.
+ If the data for graphics resources, such as textures and buffers, are still
+ available on the CPU side, such an event may not be noticeable on the
+ application level at all since graphics resources can seamlessly be
+ reinitialized then. However, applications and libraries working directly
+ with QRhi are expected to be prepared to check and handle device loss
+ situations themselves.
+
+ \note With OpenGL, applications may need to opt-in to context reset
+ notifications by setting QSurfaceFormat::ResetNotification on the
+ QOpenGLContext. This is typically done by enabling the flag in
+ QRhiGles2InitParams::format. Keep in mind however that some systems may
+ generate context resets situations even when this flag is not set.
+ */
+bool QRhi::isDeviceLost() const
+{
+ return d->isDeviceLost();
+}
+
+/*!
\return a new graphics pipeline resource.
\sa QRhiResource::release()
@@ -5180,7 +5328,17 @@ QRhiSwapChain *QRhi::newSwapChain()
\endlist
- \sa endFrame(), beginOffscreenFrame()
+ \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
+ value on failure. Some of these should be treated as soft, "try again
+ later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
+ the swapchain is to be resized or updated by calling
+ QRhiSwapChain::buildOrResize(). The application should then attempt to
+ generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
+ lost but this may also be recoverable by releasing all resources, including
+ the QRhi itself, and then recreating all resources. See isDeviceLost() for
+ further discussion.
+
+ \sa endFrame(), beginOffscreenFrame(), isDeviceLost()
*/
QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags)
{
@@ -5205,7 +5363,17 @@ QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags f
Passing QRhi::SkipPresent skips queuing the Present command or calling
swapBuffers.
- \sa beginFrame()
+ \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
+ value on failure. Some of these should be treated as soft, "try again
+ later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
+ the swapchain is to be resized or updated by calling
+ QRhiSwapChain::buildOrResize(). The application should then attempt to
+ generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
+ lost but this may also be recoverable by releasing all resources, including
+ the QRhi itself, and then recreating all resources. See isDeviceLost() for
+ further discussion.
+
+ \sa beginFrame(), isDeviceLost()
*/
QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags)
{
@@ -5419,7 +5587,7 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
const UsageState &state)
{
- auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
+ auto it = m_buffers.find(buf);
if (it != m_buffers.end()) {
if (it->access != *access) {
const QByteArray name = buf->name();
@@ -5435,12 +5603,11 @@ void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAc
}
Buffer b;
- b.buf = buf;
b.slot = slot;
b.access = *access;
b.stage = *stage;
b.stateAtPassBegin = state; // first use -> initial state
- m_buffers.append(b);
+ m_buffers.insert(buf, b);
}
static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
@@ -5459,7 +5626,7 @@ static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess acces
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
const UsageState &state)
{
- auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
+ auto it = m_textures.find(tex);
if (it != m_textures.end()) {
if (it->access != *access) {
// Different subresources of a texture may be used for both load
@@ -5483,11 +5650,10 @@ void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *a
}
Texture t;
- t.tex = tex;
t.access = *access;
t.stage = *stage;
t.stateAtPassBegin = state; // first use -> initial state
- m_textures.append(t);
+ m_textures.insert(tex, t);
}
QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 2d36c19e99..907924c788 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -52,6 +52,7 @@
#include <QSize>
#include <QMatrix4x4>
#include <QVector>
+#include <QVarLengthArray>
#include <QThread>
#include <QColor>
#include <QImage>
@@ -71,7 +72,6 @@ class QRhiCommandBuffer;
class QRhiResourceUpdateBatch;
class QRhiResourceUpdateBatchPrivate;
class QRhiProfiler;
-class QRhiShaderResourceBindingPrivate;
class Q_GUI_EXPORT QRhiDepthStencilClearValue
{
@@ -239,15 +239,42 @@ class Q_GUI_EXPORT QRhiVertexInputLayout
public:
QRhiVertexInputLayout() = default;
- QVector<QRhiVertexInputBinding> bindings() const { return m_bindings; }
- void setBindings(const QVector<QRhiVertexInputBinding> &v) { m_bindings = v; }
-
- QVector<QRhiVertexInputAttribute> attributes() const { return m_attributes; }
- void setAttributes(const QVector<QRhiVertexInputAttribute> &v) { m_attributes = v; }
+ void setBindings(std::initializer_list<QRhiVertexInputBinding> list) { m_bindings = list; }
+ template<typename InputIterator>
+ void setBindings(InputIterator first, InputIterator last)
+ {
+ m_bindings.clear();
+ std::copy(first, last, std::back_inserter(m_bindings));
+ }
+ void setBindings(const QVector<QRhiVertexInputBinding> &bindings) // compat., to be removed
+ {
+ setBindings(bindings.cbegin(), bindings.cend());
+ }
+ const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); }
+ const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); }
+ const QRhiVertexInputBinding *bindingAt(int index) const { return &m_bindings.at(index); }
+
+ void setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) { m_attributes = list; }
+ template<typename InputIterator>
+ void setAttributes(InputIterator first, InputIterator last)
+ {
+ m_attributes.clear();
+ std::copy(first, last, std::back_inserter(m_attributes));
+ }
+ void setAttributes(const QVector<QRhiVertexInputAttribute> &attributes) // compat., to be removed
+ {
+ setAttributes(attributes.cbegin(), attributes.cend());
+ }
+ const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); }
+ const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); }
private:
- QVector<QRhiVertexInputBinding> m_bindings;
- QVector<QRhiVertexInputAttribute> m_attributes;
+ QVarLengthArray<QRhiVertexInputBinding, 8> m_bindings;
+ QVarLengthArray<QRhiVertexInputAttribute, 8> m_attributes;
+
+ friend Q_GUI_EXPORT bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) Q_DECL_NOTHROW;
+ friend Q_GUI_EXPORT uint qHash(const QRhiVertexInputLayout &v, uint seed) Q_DECL_NOTHROW;
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
};
Q_DECLARE_TYPEINFO(QRhiVertexInputLayout, Q_MOVABLE_TYPE);
@@ -320,10 +347,6 @@ public:
Q_DECLARE_FLAGS(StageFlags, StageFlag)
QRhiShaderResourceBinding();
- QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
- QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
- ~QRhiShaderResourceBinding();
- void detach();
bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
@@ -344,19 +367,49 @@ public:
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
+ struct Data
+ {
+ int binding;
+ QRhiShaderResourceBinding::StageFlags stage;
+ QRhiShaderResourceBinding::Type type;
+ struct UniformBufferData {
+ QRhiBuffer *buf;
+ int offset;
+ int maybeSize;
+ bool hasDynamicOffset;
+ };
+ struct SampledTextureData {
+ QRhiTexture *tex;
+ QRhiSampler *sampler;
+ };
+ struct StorageImageData {
+ QRhiTexture *tex;
+ int level;
+ };
+ struct StorageBufferData {
+ QRhiBuffer *buf;
+ int offset;
+ int maybeSize;
+ };
+ union {
+ UniformBufferData ubuf;
+ SampledTextureData stex;
+ StorageImageData simage;
+ StorageBufferData sbuf;
+ } u;
+ };
+
+ Data *data() { return &d; }
+ const Data *data() const { return &d; }
+
private:
- QRhiShaderResourceBindingPrivate *d;
- friend class QRhiShaderResourceBindingPrivate;
- friend Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
- friend Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &, const QRhiShaderResourceBinding &) Q_DECL_NOTHROW;
- friend Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &, uint) Q_DECL_NOTHROW;
-#ifndef QT_NO_DEBUG_STREAM
- friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
-#endif
+ Data d;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
+Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_MOVABLE_TYPE);
+
Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) Q_DECL_NOTHROW;
Q_GUI_EXPORT uint qHash(const QRhiShaderResourceBinding &b, uint seed = 0) Q_DECL_NOTHROW;
@@ -412,8 +465,16 @@ public:
QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiRenderBuffer *depthStencilBuffer);
QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiTexture *depthTexture);
- QVector<QRhiColorAttachment> colorAttachments() const { return m_colorAttachments; }
- void setColorAttachments(const QVector<QRhiColorAttachment> &att) { m_colorAttachments = att; }
+ void setColorAttachments(std::initializer_list<QRhiColorAttachment> list) { m_colorAttachments = list; }
+ template<typename InputIterator>
+ void setColorAttachments(InputIterator first, InputIterator last)
+ {
+ m_colorAttachments.clear();
+ std::copy(first, last, std::back_inserter(m_colorAttachments));
+ }
+ const QRhiColorAttachment *cbeginColorAttachments() const { return m_colorAttachments.cbegin(); }
+ const QRhiColorAttachment *cendColorAttachments() const { return m_colorAttachments.cend(); }
+ const QRhiColorAttachment *colorAttachmentAt(int index) const { return &m_colorAttachments.at(index); }
QRhiRenderBuffer *depthStencilBuffer() const { return m_depthStencilBuffer; }
void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) { m_depthStencilBuffer = renderBuffer; }
@@ -422,7 +483,7 @@ public:
void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; }
private:
- QVector<QRhiColorAttachment> m_colorAttachments;
+ QVarLengthArray<QRhiColorAttachment, 8> m_colorAttachments;
QRhiRenderBuffer *m_depthStencilBuffer = nullptr;
QRhiTexture *m_depthTexture = nullptr;
};
@@ -489,14 +550,23 @@ class Q_GUI_EXPORT QRhiTextureUploadDescription
public:
QRhiTextureUploadDescription() = default;
QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry);
- QRhiTextureUploadDescription(const QVector<QRhiTextureUploadEntry> &entries);
-
- QVector<QRhiTextureUploadEntry> entries() const { return m_entries; }
- void setEntries(const QVector<QRhiTextureUploadEntry> &entries) { m_entries = entries; }
- void append(const QRhiTextureUploadEntry &entry);
+ QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list);
+ QRhiTextureUploadDescription(const QVector<QRhiTextureUploadEntry> &entries) // compat., to be removed
+ : m_entries(entries.cbegin(), entries.cend())
+ { }
+
+ void setEntries(std::initializer_list<QRhiTextureUploadEntry> list) { m_entries = list; }
+ template<typename InputIterator>
+ void setEntries(InputIterator first, InputIterator last)
+ {
+ m_entries.clear();
+ std::copy(first, last, std::back_inserter(m_entries));
+ }
+ const QRhiTextureUploadEntry *cbeginEntries() const { return m_entries.cbegin(); }
+ const QRhiTextureUploadEntry *cendEntries() const { return m_entries.cend(); }
private:
- QVector<QRhiTextureUploadEntry> m_entries;
+ QVarLengthArray<QRhiTextureUploadEntry, 16> m_entries;
};
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE);
@@ -900,8 +970,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
public:
QRhiResource::Type resourceType() const override;
- QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
- void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
+ void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
+
+ template<typename InputIterator>
+ void setBindings(InputIterator first, InputIterator last)
+ {
+ m_bindings.clear();
+ std::copy(first, last, std::back_inserter(m_bindings));
+ }
+
+ void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed
+ {
+ setBindings(bindings.cbegin(), bindings.cend());
+ }
+
+ const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
+ const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
@@ -909,7 +993,7 @@ public:
protected:
QRhiShaderResourceBindings(QRhiImplementation *rhi);
- QVector<QRhiShaderResourceBinding> m_bindings;
+ QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
#endif
@@ -932,6 +1016,7 @@ public:
enum Topology {
Triangles,
TriangleStrip,
+ TriangleFan,
Lines,
LineStrip,
Points
@@ -1040,8 +1125,15 @@ public:
FrontFace frontFace() const { return m_frontFace; }
void setFrontFace(FrontFace f) { m_frontFace = f; }
- QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
- void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
+ void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
+ template<typename InputIterator>
+ void setTargetBlends(InputIterator first, InputIterator last)
+ {
+ m_targetBlends.clear();
+ std::copy(first, last, std::back_inserter(m_targetBlends));
+ }
+ const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
+ const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
bool hasDepthTest() const { return m_depthTest; }
void setDepthTest(bool enable) { m_depthTest = enable; }
@@ -1073,8 +1165,19 @@ public:
float lineWidth() const { return m_lineWidth; }
void setLineWidth(float width) { m_lineWidth = width; }
- QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
- void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
+ void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
+ template<typename InputIterator>
+ void setShaderStages(InputIterator first, InputIterator last)
+ {
+ m_shaderStages.clear();
+ std::copy(first, last, std::back_inserter(m_shaderStages));
+ }
+ void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed
+ {
+ setShaderStages(stages.cbegin(), stages.cend());
+ }
+ const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
+ const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
@@ -1093,7 +1196,7 @@ protected:
Topology m_topology = Triangles;
CullMode m_cullMode = None;
FrontFace m_frontFace = CCW;
- QVector<TargetBlend> m_targetBlends;
+ QVarLengthArray<TargetBlend, 8> m_targetBlends;
bool m_depthTest = false;
bool m_depthWrite = false;
CompareOp m_depthOp = Less;
@@ -1104,7 +1207,7 @@ protected:
quint32 m_stencilWriteMask = 0xFF;
int m_sampleCount = 1;
float m_lineWidth = 1.0f;
- QVector<QRhiShaderStage> m_shaderStages;
+ QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
QRhiVertexInputLayout m_vertexInputLayout;
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
@@ -1251,6 +1354,12 @@ struct Q_GUI_EXPORT QRhiReadbackResult
QByteArray data;
}; // non-movable due to the std::function
+struct Q_GUI_EXPORT QRhiBufferReadbackResult
+{
+ std::function<void()> completed = nullptr;
+ QByteArray data;
+};
+
class Q_GUI_EXPORT QRhiResourceUpdateBatch
{
public:
@@ -1263,6 +1372,7 @@ public:
void updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
void uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
+ void readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result);
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
void uploadTexture(QRhiTexture *tex, const QImage &image);
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
@@ -1294,7 +1404,8 @@ public:
enum Flag {
EnableProfiling = 1 << 0,
- EnableDebugMarkers = 1 << 1
+ EnableDebugMarkers = 1 << 1,
+ PreferSoftwareRenderer = 1 << 2
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -1322,7 +1433,10 @@ public:
WideLines,
VertexShaderPointSize,
BaseVertex,
- BaseInstance
+ BaseInstance,
+ TriangleFanTopology,
+ ReadBackNonUniformBuffer,
+ ReadBackNonBaseMipLevel
};
enum BeginFrameFlag {
@@ -1413,13 +1527,17 @@ public:
int resourceLimit(ResourceLimit limit) const;
const QRhiNativeHandles *nativeHandles();
- void makeThreadLocalNativeContextCurrent();
+ bool makeThreadLocalNativeContextCurrent();
QRhiProfiler *profiler();
static const int MAX_LAYERS = 6; // cubemaps only
static const int MAX_LEVELS = 16; // a width and/or height of 65536 should be enough for everyone
+ void releaseCachedResources();
+
+ bool isDeviceLost() const;
+
protected:
QRhi();
diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h
index 0914cf268b..baffe28202 100644
--- a/src/gui/rhi/qrhi_p_p.h
+++ b/src/gui/rhi/qrhi_p_p.h
@@ -156,7 +156,9 @@ public:
virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
virtual const QRhiNativeHandles *nativeHandles() = 0;
virtual void sendVMemStatsToProfiler() = 0;
- virtual void makeThreadLocalNativeContextCurrent() = 0;
+ virtual bool makeThreadLocalNativeContextCurrent() = 0;
+ virtual void releaseCachedResources() = 0;
+ virtual bool isDeviceLost() const = 0;
bool isCompressedFormat(QRhiTexture::Format format) const;
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
@@ -203,8 +205,12 @@ public:
cleanupCallbacks.append(callback);
}
+ bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
+
QRhi *q;
+ static const int MAX_SHADER_CACHE_ENTRIES = 128;
+
protected:
bool debugMarkers = false;
int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
@@ -214,7 +220,7 @@ private:
QRhi::Implementation implType;
QThread *implThread;
QRhiProfiler profiler;
- QVector<QRhiResourceUpdateBatch *> resUpdPool;
+ QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
QBitArray resUpdPoolMap;
QSet<QRhiResource *> resources;
QSet<QRhiResource *> pendingReleaseAndDestroyResources;
@@ -229,27 +235,37 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
T *x, T *y, T *w, T *h)
{
// x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
- // Vulkan/Metal/D3D. We also need proper clamping since some
- // validation/debug layers are allergic to out of bounds scissor or
- // viewport rects.
+ // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
+ // negative x or y, and partly or completely out of bounds rects are
+ // allowed. The only thing the input here cannot have is a negative width
+ // or height. We must handle all other input gracefully, clamping to a zero
+ // width or height rect in the worst case, and ensuring the resulting rect
+ // is inside the rendertarget's bounds because some APIs' validation/debug
+ // layers are allergic to out of bounds scissor or viewport rects.
const T outputWidth = outputSize.width();
const T outputHeight = outputSize.height();
const T inputWidth = r[2];
const T inputHeight = r[3];
- *x = qMax<T>(0, r[0]);
- *y = qMax<T>(0, outputHeight - (r[1] + inputHeight));
- *w = inputWidth;
- *h = inputHeight;
-
- if (*x >= outputWidth || *y >= outputHeight)
+ if (inputWidth < 0 || inputHeight < 0)
return false;
+ *x = r[0];
+ *y = outputHeight - (r[1] + inputHeight);
+
+ const T widthOffset = *x < 0 ? -*x : 0;
+ const T heightOffset = *y < 0 ? -*y : 0;
+
+ *x = qBound<T>(0, *x, outputWidth - 1);
+ *y = qBound<T>(0, *y, outputHeight - 1);
+ *w = qMax<T>(0, inputWidth - widthOffset);
+ *h = qMax<T>(0, inputHeight - heightOffset);
+
if (*x + *w > outputWidth)
- *w = outputWidth - *x;
+ *w = qMax<T>(0, outputWidth - *x - 1);
if (*y + *h > outputHeight)
- *h = outputHeight - *y;
+ *h = qMax<T>(0, outputHeight - *y - 1);
return true;
}
@@ -257,26 +273,49 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
class QRhiResourceUpdateBatchPrivate
{
public:
- struct DynamicBufferUpdate {
- DynamicBufferUpdate() { }
- DynamicBufferUpdate(QRhiBuffer *buf_, int offset_, int size_, const void *data_)
- : buf(buf_), offset(offset_), data(reinterpret_cast<const char *>(data_), size_)
- { }
-
- QRhiBuffer *buf = nullptr;
- int offset = 0;
+ struct BufferOp {
+ enum Type {
+ DynamicUpdate,
+ StaticUpload,
+ Read
+ };
+ Type type;
+ QRhiBuffer *buf;
+ int offset;
QByteArray data;
- };
+ int readSize;
+ QRhiBufferReadbackResult *result;
- struct StaticBufferUpload {
- StaticBufferUpload() { }
- StaticBufferUpload(QRhiBuffer *buf_, int offset_, int size_, const void *data_)
- : buf(buf_), offset(offset_), data(reinterpret_cast<const char *>(data_), size_ ? size_ : buf_->size())
- { }
+ static BufferOp dynamicUpdate(QRhiBuffer *buf, int offset, int size, const void *data)
+ {
+ BufferOp op;
+ op.type = DynamicUpdate;
+ op.buf = buf;
+ op.offset = offset;
+ op.data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
+ return op;
+ }
- QRhiBuffer *buf = nullptr;
- int offset = 0;
- QByteArray data;
+ static BufferOp staticUpload(QRhiBuffer *buf, int offset, int size, const void *data)
+ {
+ BufferOp op;
+ op.type = StaticUpload;
+ op.buf = buf;
+ op.offset = offset;
+ op.data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
+ return op;
+ }
+
+ static BufferOp read(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
+ {
+ BufferOp op;
+ op.type = Read;
+ op.buf = buf;
+ op.offset = offset;
+ op.readSize = size;
+ op.result = result;
+ return op;
+ }
};
struct TextureOp {
@@ -284,74 +323,62 @@ public:
Upload,
Copy,
Read,
- MipGen
+ GenMips
};
Type type;
- struct SUpload {
- QRhiTexture *tex = nullptr;
- // Specifying multiple uploads for a subresource must be supported.
- // In the backend this can then end up, where applicable, as a
- // single, batched copy operation with only one set of barriers.
- // This helps when doing for example glyph cache fills.
- QVector<QRhiTextureSubresourceUploadDescription> subresDesc[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
- } upload;
- struct SCopy {
- QRhiTexture *dst = nullptr;
- QRhiTexture *src = nullptr;
- QRhiTextureCopyDescription desc;
- } copy;
- struct SRead {
- QRhiReadbackDescription rb;
- QRhiReadbackResult *result;
- } read;
- struct SMipGen {
- QRhiTexture *tex = nullptr;
- int layer = 0;
- } mipgen;
-
- static TextureOp textureUpload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
+ QRhiTexture *dst;
+ // Specifying multiple uploads for a subresource must be supported.
+ // In the backend this can then end up, where applicable, as a
+ // single, batched copy operation with only one set of barriers.
+ // This helps when doing for example glyph cache fills.
+ QVector<QRhiTextureSubresourceUploadDescription> subresDesc[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
+ QRhiTexture *src;
+ QRhiTextureCopyDescription desc;
+ QRhiReadbackDescription rb;
+ QRhiReadbackResult *result;
+ int layer;
+
+ static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
{
TextureOp op;
op.type = Upload;
- op.upload.tex = tex;
- const QVector<QRhiTextureUploadEntry> &entries(desc.entries());
- for (const QRhiTextureUploadEntry &entry : entries)
- op.upload.subresDesc[entry.layer()][entry.level()].append(entry.description());
+ op.dst = tex;
+ for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
+ op.subresDesc[it->layer()][it->level()].append(it->description());
return op;
}
- static TextureOp textureCopy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
+ static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
{
TextureOp op;
op.type = Copy;
- op.copy.dst = dst;
- op.copy.src = src;
- op.copy.desc = desc;
+ op.dst = dst;
+ op.src = src;
+ op.desc = desc;
return op;
}
- static TextureOp textureRead(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
+ static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
TextureOp op;
op.type = Read;
- op.read.rb = rb;
- op.read.result = result;
+ op.rb = rb;
+ op.result = result;
return op;
}
- static TextureOp textureMipGen(QRhiTexture *tex, int layer)
+ static TextureOp genMips(QRhiTexture *tex, int layer)
{
TextureOp op;
- op.type = MipGen;
- op.mipgen.tex = tex;
- op.mipgen.layer = layer;
+ op.type = GenMips;
+ op.dst = tex;
+ op.layer = layer;
return op;
}
};
- QVector<DynamicBufferUpdate> dynamicBufferUpdates;
- QVector<StaticBufferUpload> staticBufferUploads;
- QVector<TextureOp> textureOps;
+ QVarLengthArray<BufferOp, 1024> bufferOps;
+ QVarLengthArray<TextureOp, 256> textureOps;
QRhiResourceUpdateBatch *q = nullptr;
QRhiImplementation *rhi = nullptr;
@@ -363,61 +390,9 @@ public:
static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
};
-Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::BufferOp, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
-class Q_GUI_EXPORT QRhiShaderResourceBindingPrivate
-{
-public:
- QRhiShaderResourceBindingPrivate()
- : ref(1)
- {
- }
-
- QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other)
- : ref(1),
- binding(other->binding),
- stage(other->stage),
- type(other->type),
- u(other->u)
- {
- }
-
- static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; }
- static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; }
-
- QAtomicInt ref;
- int binding;
- QRhiShaderResourceBinding::StageFlags stage;
- QRhiShaderResourceBinding::Type type;
- struct UniformBufferData {
- QRhiBuffer *buf;
- int offset;
- int maybeSize;
- bool hasDynamicOffset;
- };
- struct SampledTextureData {
- QRhiTexture *tex;
- QRhiSampler *sampler;
- };
- struct StorageImageData {
- QRhiTexture *tex;
- int level;
- };
- struct StorageBufferData {
- QRhiBuffer *buf;
- int offset;
- int maybeSize;
- };
- union {
- UniformBufferData ubuf;
- SampledTextureData stex;
- StorageImageData simage;
- StorageBufferData sbuf;
- } u;
-};
-
template<typename T>
struct QRhiBatchedBindings
{
@@ -540,28 +515,32 @@ public:
const UsageState &state);
struct Buffer {
- QRhiBuffer *buf;
int slot;
BufferAccess access;
BufferStage stage;
UsageState stateAtPassBegin;
};
- const QVector<Buffer> *buffers() const { return &m_buffers; }
+
+ using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
+ BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
+ BufferIterator cendBuffers() const { return m_buffers.cend(); }
struct Texture {
- QRhiTexture *tex;
TextureAccess access;
TextureStage stage;
UsageState stateAtPassBegin;
};
- const QVector<Texture> *textures() const { return &m_textures; }
+
+ using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
+ TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
+ TextureIterator cendTextures() const { return m_textures.cend(); }
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
private:
- QVector<Buffer> m_buffers;
- QVector<Texture> m_textures;
+ QHash<QRhiBuffer *, Buffer> m_buffers;
+ QHash<QRhiTexture *, Texture> m_textures;
};
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_MOVABLE_TYPE);
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 3e136cdb80..717f3e6d6c 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -36,6 +36,7 @@
#include "qrhid3d11_p_p.h"
#include "qshader_p.h"
+#include "cs_tdr_p.h"
#include <QWindow>
#include <QOperatingSystemVersion>
#include <qmath.h>
@@ -118,10 +119,20 @@ QT_BEGIN_NAMESPACE
\c{ID3D11Texture2D *}.
*/
+// help mingw with its ancient sdk headers
+#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
+#define DXGI_ADAPTER_FLAG_SOFTWARE 2
+#endif
+
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice)
- : ofr(this)
+ : ofr(this),
+ deviceCurse(this)
{
debugLayer = params->enableDebugLayer;
+
+ deviceCurse.framesToActivate = params->framesUntilKillingDeviceViaTdr;
+ deviceCurse.permanent = params->repeatDeviceKill;
+
importedDevice = importDevice != nullptr;
if (importedDevice) {
dev = reinterpret_cast<ID3D11Device *>(importDevice->dev);
@@ -155,7 +166,7 @@ static QString comErrorMessage(HRESULT hr)
}
template <class Int>
-static inline Int aligned(Int v, Int byteAlign)
+inline Int aligned(Int v, Int byteAlign)
{
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
@@ -166,7 +177,7 @@ static IDXGIFactory1 *createDXGIFactory2()
if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) {
using PtrCreateDXGIFactory2 = HRESULT (WINAPI *)(UINT, REFIID, void **);
QSystemLibrary dxgilib(QStringLiteral("dxgi"));
- if (auto createDXGIFactory2 = (PtrCreateDXGIFactory2)dxgilib.resolve("CreateDXGIFactory2")) {
+ if (auto createDXGIFactory2 = reinterpret_cast<PtrCreateDXGIFactory2>(dxgilib.resolve("CreateDXGIFactory2"))) {
const HRESULT hr = createDXGIFactory2(0, IID_IDXGIFactory2, reinterpret_cast<void **>(&result));
if (FAILED(hr)) {
qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s", qPrintable(comErrorMessage(hr)));
@@ -221,11 +232,29 @@ bool QRhiD3D11::create(QRhi::Flags flags)
int requestedAdapterIndex = -1;
if (qEnvironmentVariableIsSet("QT_D3D_ADAPTER_INDEX"))
requestedAdapterIndex = qEnvironmentVariableIntValue("QT_D3D_ADAPTER_INDEX");
- for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
+
+ if (requestedAdapterIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
+ DXGI_ADAPTER_DESC1 desc;
+ adapter->GetDesc1(&desc);
+ adapter->Release();
+ if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
+ requestedAdapterIndex = adapterIndex;
+ break;
+ }
+ }
+ }
+
+ for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
- const QString name = QString::fromUtf16((char16_t *) desc.Description);
- qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (flags 0x%x)", adapterIndex, qPrintable(name), desc.Flags);
+ const QString name = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description));
+ qCDebug(QRHI_LOG_INFO, "Adapter %d: '%s' (vendor 0x%X device 0x%X flags 0x%X)",
+ adapterIndex,
+ qPrintable(name),
+ desc.VendorId,
+ desc.DeviceId,
+ desc.Flags);
if (!adapterToUse && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
adapterToUse = adapter;
qCDebug(QRHI_LOG_INFO, " using this adapter");
@@ -261,16 +290,33 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (FAILED(context->QueryInterface(IID_ID3DUserDefinedAnnotation, reinterpret_cast<void **>(&annotations))))
annotations = nullptr;
+ deviceLost = false;
+
nativeHandlesStruct.dev = dev;
nativeHandlesStruct.context = context;
+ if (deviceCurse.framesToActivate > 0)
+ deviceCurse.initResources();
+
return true;
}
+void QRhiD3D11::clearShaderCache()
+{
+ for (Shader &s : m_shaderCache)
+ s.s->Release();
+
+ m_shaderCache.clear();
+}
+
void QRhiD3D11::destroy()
{
finishActiveReadbacks();
+ clearShaderCache();
+
+ deviceCurse.releaseResources();
+
if (annotations) {
annotations->Release();
annotations = nullptr;
@@ -322,9 +368,9 @@ DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleCount(int sampleCount) const
return desc;
}
- desc.Count = s;
+ desc.Count = UINT(s);
if (s > 1)
- desc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
+ desc.Quality = UINT(D3D11_STANDARD_MULTISAMPLE_PATTERN);
else
desc.Quality = 0;
@@ -423,6 +469,12 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::BaseInstance:
return true;
+ case QRhi::TriangleFanTopology:
+ return false;
+ case QRhi::ReadBackNonUniformBuffer:
+ return true;
+ case QRhi::ReadBackNonBaseMipLevel:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -456,9 +508,20 @@ void QRhiD3D11::sendVMemStatsToProfiler()
// nothing to do here
}
-void QRhiD3D11::makeThreadLocalNativeContextCurrent()
+bool QRhiD3D11::makeThreadLocalNativeContextCurrent()
{
- // nothing to do here
+ // not applicable
+ return false;
+}
+
+void QRhiD3D11::releaseCachedResources()
+{
+ clearShaderCache();
+}
+
+bool QRhiD3D11::isDeviceLost() const
+{
+ return deviceLost;
}
QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
@@ -541,7 +604,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
bool hasDynamicOffsetInSrb = false;
bool srbUpdate = false;
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -640,7 +703,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
uint *p = cmd.args.bindShaderResources.dynamicOffsetPairs;
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
- const uint binding = dynOfs.first;
+ const uint binding = uint(dynOfs.first);
Q_ASSERT(aligned(dynOfs.second, quint32(256)) == dynOfs.second);
const uint offsetInConstants = dynOfs.second / 16;
*p++ = binding;
@@ -685,13 +748,14 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb,
cmd.cmd = QD3D11CommandBuffer::Command::BindVertexBuffers;
cmd.args.bindVertexBuffers.startSlot = startBinding;
cmd.args.bindVertexBuffers.slotCount = bindingCount;
- const QVector<QRhiVertexInputBinding> inputBindings =
- QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline)->m_vertexInputLayout.bindings();
- for (int i = 0, ie = qMin(bindingCount, inputBindings.count()); i != ie; ++i) {
+ QD3D11GraphicsPipeline *psD = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline);
+ const QRhiVertexInputLayout &inputLayout(psD->m_vertexInputLayout);
+ const int inputBindingCount = inputLayout.cendBindings() - inputLayout.cbeginBindings();
+ for (int i = 0, ie = qMin(bindingCount, inputBindingCount); i != ie; ++i) {
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
cmd.args.bindVertexBuffers.buffers[i] = bufD->buffer;
cmd.args.bindVertexBuffers.offsets[i] = bindings[i].second;
- cmd.args.bindVertexBuffers.strides[i] = inputBindings[i].stride();
+ cmd.args.bindVertexBuffers.strides[i] = inputLayout.bindingAt(i)->stride();
}
cbD->commands.append(cmd);
}
@@ -776,10 +840,10 @@ void QRhiD3D11::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::BlendConstants;
cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentGraphicsPipeline);
- cmd.args.blendConstants.c[0] = c.redF();
- cmd.args.blendConstants.c[1] = c.greenF();
- cmd.args.blendConstants.c[2] = c.blueF();
- cmd.args.blendConstants.c[3] = c.alphaF();
+ cmd.args.blendConstants.c[0] = float(c.redF());
+ cmd.args.blendConstants.c[1] = float(c.greenF());
+ cmd.args.blendConstants.c[2] = float(c.blueF());
+ cmd.args.blendConstants.c[3] = float(c.alphaF());
cbD->commands.append(cmd);
}
@@ -977,8 +1041,14 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
if (!flags.testFlag(QRhi::SkipPresent)) {
const UINT presentFlags = 0;
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
- if (FAILED(hr))
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
+ qWarning("Device loss detected in Present()");
+ deviceLost = true;
+ return QRhi::FrameOpDeviceLost;
+ } else if (FAILED(hr)) {
qWarning("Failed to present: %s", qPrintable(comErrorMessage(hr)));
+ return QRhi::FrameOpError;
+ }
// move on to the next buffer
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
@@ -988,6 +1058,20 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
swapChainD->frameCount += 1;
contextState.currentSwapChain = nullptr;
+
+ if (deviceCurse.framesToActivate > 0) {
+ deviceCurse.framesLeft -= 1;
+ if (deviceCurse.framesLeft == 0) {
+ deviceCurse.framesLeft = deviceCurse.framesToActivate;
+ if (!deviceCurse.permanent)
+ deviceCurse.framesToActivate = -1;
+
+ deviceCurse.activate();
+ } else if (deviceCurse.framesLeft % 100 == 0) {
+ qDebug("Impending doom: %d frames left", deviceCurse.framesLeft);
+ }
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -1161,7 +1245,7 @@ QRhi::FrameOpResult QRhiD3D11::finish()
void QRhiD3D11::enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc)
{
- UINT subres = D3D11CalcSubresource(level, layer, texD->mipLevelCount);
+ UINT subres = D3D11CalcSubresource(UINT(level), UINT(layer), texD->mipLevelCount);
const QPoint dp = subresDesc.destinationTopLeft();
D3D11_BOX box;
box.front = 0;
@@ -1192,13 +1276,13 @@ void QRhiD3D11::enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cb
} else {
cmd.args.updateSubRes.src = cbD->retainImage(img);
}
- box.left = dp.x();
- box.top = dp.y();
- box.right = dp.x() + size.width();
- box.bottom = dp.y() + size.height();
+ box.left = UINT(dp.x());
+ box.top = UINT(dp.y());
+ box.right = UINT(dp.x() + size.width());
+ box.bottom = UINT(dp.y() + size.height());
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
- cmd.args.updateSubRes.srcRowPitch = bpl;
+ cmd.args.updateSubRes.srcRowPitch = UINT(bpl);
} else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
: subresDesc.sourceSize();
@@ -1208,10 +1292,10 @@ void QRhiD3D11::enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cb
// Everything must be a multiple of the block width and
// height, so e.g. a mip level of size 2x2 will be 4x4 when it
// comes to the actual data.
- box.left = aligned(dp.x(), blockDim.width());
- box.top = aligned(dp.y(), blockDim.height());
- box.right = aligned(dp.x() + size.width(), blockDim.width());
- box.bottom = aligned(dp.y() + size.height(), blockDim.height());
+ box.left = UINT(aligned(dp.x(), blockDim.width()));
+ box.top = UINT(aligned(dp.y(), blockDim.height()));
+ box.right = UINT(aligned(dp.x() + size.width(), blockDim.width()));
+ box.bottom = UINT(aligned(dp.y() + size.height(), blockDim.height()));
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
@@ -1220,12 +1304,11 @@ void QRhiD3D11::enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cb
const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
: subresDesc.sourceSize();
quint32 bpl = 0;
- QSize blockDim;
textureFormatInfo(texD->m_format, size, &bpl, nullptr);
- box.left = dp.x();
- box.top = dp.y();
- box.right = dp.x() + size.width();
- box.bottom = dp.y() + size.height();
+ box.left = UINT(dp.x());
+ box.top = UINT(dp.y());
+ box.right = UINT(dp.x() + size.width());
+ box.bottom = UINT(dp.y() + size.height());
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.src = cbD->retainData(subresDesc.data());
@@ -1244,84 +1327,128 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
- QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
- Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- memcpy(bufD->dynBuf.data() + u.offset, u.data.constData(), u.data.size());
- bufD->hasPendingDynamicUpdates = true;
- }
-
- for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
- QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
- Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
- QD3D11CommandBuffer::Command cmd;
- cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
- cmd.args.updateSubRes.dst = bufD->buffer;
- cmd.args.updateSubRes.dstSubRes = 0;
- cmd.args.updateSubRes.src = cbD->retainData(u.data);
- cmd.args.updateSubRes.srcRowPitch = 0;
- // Specify the region (even when offset is 0 and all data is provided)
- // since the ID3D11Buffer's size is rounded up to be a multiple of 256
- // while the data we have has the original size.
- D3D11_BOX box;
- box.left = u.offset;
- box.top = box.front = 0;
- box.back = box.bottom = 1;
- box.right = u.offset + u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
- cmd.args.updateSubRes.hasDstBox = true;
- cmd.args.updateSubRes.dstBox = box;
- cbD->commands.append(cmd);
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
+ if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
+ QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
+ Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
+ memcpy(bufD->dynBuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
+ bufD->hasPendingDynamicUpdates = true;
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
+ QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
+ Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
+ QD3D11CommandBuffer::Command cmd;
+ cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
+ cmd.args.updateSubRes.dst = bufD->buffer;
+ cmd.args.updateSubRes.dstSubRes = 0;
+ cmd.args.updateSubRes.src = cbD->retainData(u.data);
+ cmd.args.updateSubRes.srcRowPitch = 0;
+ // Specify the region (even when offset is 0 and all data is provided)
+ // since the ID3D11Buffer's size is rounded up to be a multiple of 256
+ // while the data we have has the original size.
+ D3D11_BOX box;
+ box.left = UINT(u.offset);
+ box.top = box.front = 0;
+ box.back = box.bottom = 1;
+ box.right = UINT(u.offset + u.data.size()); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
+ cmd.args.updateSubRes.hasDstBox = true;
+ cmd.args.updateSubRes.dstBox = box;
+ cbD->commands.append(cmd);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
+ QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
+ if (bufD->m_type == QRhiBuffer::Dynamic) {
+ u.result->data.resize(u.readSize);
+ memcpy(u.result->data.data(), bufD->dynBuf.constData() + u.offset, size_t(u.readSize));
+ } else {
+ BufferReadback readback;
+ readback.result = u.result;
+ readback.byteSize = u.readSize;
+
+ D3D11_BUFFER_DESC desc;
+ memset(&desc, 0, sizeof(desc));
+ desc.ByteWidth = readback.byteSize;
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
+ if (FAILED(hr)) {
+ qWarning("Failed to create buffer: %s", qPrintable(comErrorMessage(hr)));
+ continue;
+ }
+ QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(readback.stagingBuf)), bufD, readback.byteSize));
+
+ QD3D11CommandBuffer::Command cmd;
+ cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
+ cmd.args.copySubRes.dst = readback.stagingBuf;
+ cmd.args.copySubRes.dstSubRes = 0;
+ cmd.args.copySubRes.dstX = 0;
+ cmd.args.copySubRes.dstY = 0;
+ cmd.args.copySubRes.src = bufD->buffer;
+ cmd.args.copySubRes.srcSubRes = 0;
+ cmd.args.copySubRes.hasSrcBox = true;
+ D3D11_BOX box;
+ box.left = UINT(u.offset);
+ box.top = box.front = 0;
+ box.back = box.bottom = 1;
+ box.right = UINT(u.offset + u.readSize);
+ cmd.args.copySubRes.srcBox = box;
+ cbD->commands.append(cmd);
+
+ activeBufferReadbacks.append(readback);
+ }
+ if (u.result->completed)
+ u.result->completed();
+ }
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
- QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.upload.tex);
+ QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.dst);
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
}
}
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
- Q_ASSERT(u.copy.src && u.copy.dst);
- QD3D11Texture *srcD = QRHI_RES(QD3D11Texture, u.copy.src);
- QD3D11Texture *dstD = QRHI_RES(QD3D11Texture, u.copy.dst);
- UINT srcSubRes = D3D11CalcSubresource(u.copy.desc.sourceLevel(), u.copy.desc.sourceLayer(), srcD->mipLevelCount);
- UINT dstSubRes = D3D11CalcSubresource(u.copy.desc.destinationLevel(), u.copy.desc.destinationLayer(), dstD->mipLevelCount);
- const QPoint dp = u.copy.desc.destinationTopLeft();
- const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
- const QPoint sp = u.copy.desc.sourceTopLeft();
+ Q_ASSERT(u.src && u.dst);
+ QD3D11Texture *srcD = QRHI_RES(QD3D11Texture, u.src);
+ QD3D11Texture *dstD = QRHI_RES(QD3D11Texture, u.dst);
+ UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), UINT(u.desc.sourceLayer()), srcD->mipLevelCount);
+ UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), UINT(u.desc.destinationLayer()), dstD->mipLevelCount);
+ const QPoint dp = u.desc.destinationTopLeft();
+ const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
+ const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
+ const QPoint sp = u.desc.sourceTopLeft();
D3D11_BOX srcBox;
- srcBox.left = sp.x();
- srcBox.top = sp.y();
+ srcBox.left = UINT(sp.x());
+ srcBox.top = UINT(sp.y());
srcBox.front = 0;
// back, right, bottom are exclusive
- srcBox.right = srcBox.left + size.width();
- srcBox.bottom = srcBox.top + size.height();
+ srcBox.right = srcBox.left + UINT(copySize.width());
+ srcBox.bottom = srcBox.top + UINT(copySize.height());
srcBox.back = 1;
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
cmd.args.copySubRes.dst = dstD->tex;
cmd.args.copySubRes.dstSubRes = dstSubRes;
- cmd.args.copySubRes.dstX = dp.x();
- cmd.args.copySubRes.dstY = dp.y();
+ cmd.args.copySubRes.dstX = UINT(dp.x());
+ cmd.args.copySubRes.dstY = UINT(dp.y());
cmd.args.copySubRes.src = srcD->tex;
cmd.args.copySubRes.srcSubRes = srcSubRes;
cmd.args.copySubRes.hasSrcBox = true;
cmd.args.copySubRes.srcBox = srcBox;
cbD->commands.append(cmd);
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
- ActiveReadback aRb;
- aRb.desc = u.read.rb;
- aRb.result = u.read.result;
+ TextureReadback readback;
+ readback.desc = u.rb;
+ readback.result = u.result;
ID3D11Resource *src;
DXGI_FORMAT dxgiFormat;
QSize pixelSize;
QRhiTexture::Format format;
UINT subres = 0;
- QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.read.rb.texture());
+ QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.rb.texture());
QD3D11SwapChain *swapChainD = nullptr;
if (texD) {
@@ -1331,9 +1458,9 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
src = texD->tex;
dxgiFormat = texD->dxgiFormat;
- pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize) : texD->m_pixelSize;
+ pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
format = texD->m_format;
- subres = D3D11CalcSubresource(u.read.rb.level(), u.read.rb.layer(), texD->mipLevelCount);
+ subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(u.rb.layer()), texD->mipLevelCount);
} else {
Q_ASSERT(contextState.currentSwapChain);
swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
@@ -1356,14 +1483,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
if (format == QRhiTexture::UnknownFormat)
continue;
}
- quint32 bufSize = 0;
+ quint32 byteSize = 0;
quint32 bpl = 0;
- textureFormatInfo(format, pixelSize, &bpl, &bufSize);
+ textureFormatInfo(format, pixelSize, &bpl, &byteSize);
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.Width = pixelSize.width();
- desc.Height = pixelSize.height();
+ desc.Width = UINT(pixelSize.width());
+ desc.Height = UINT(pixelSize.height());
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = dxgiFormat;
@@ -1376,9 +1503,9 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
qWarning("Failed to create readback staging texture: %s", qPrintable(comErrorMessage(hr)));
return;
}
- QRHI_PROF_F(newReadbackBuffer(quint64(quintptr(stagingTex)),
+ QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(stagingTex)),
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
- bufSize));
+ byteSize));
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
@@ -1391,18 +1518,18 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.copySubRes.hasSrcBox = false;
cbD->commands.append(cmd);
- aRb.stagingTex = stagingTex;
- aRb.bufSize = bufSize;
- aRb.bpl = bpl;
- aRb.pixelSize = pixelSize;
- aRb.format = format;
+ readback.stagingTex = stagingTex;
+ readback.byteSize = byteSize;
+ readback.bpl = bpl;
+ readback.pixelSize = pixelSize;
+ readback.format = format;
- activeReadbacks.append(aRb);
- } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
- Q_ASSERT(u.mipgen.tex->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
+ activeTextureReadbacks.append(readback);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
+ Q_ASSERT(u.dst->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::GenMip;
- cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.mipgen.tex)->srv;
+ cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.dst)->srv;
cbD->commands.append(cmd);
}
}
@@ -1415,37 +1542,58 @@ void QRhiD3D11::finishActiveReadbacks()
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
- const QRhiD3D11::ActiveReadback &aRb(activeReadbacks[i]);
- aRb.result->format = aRb.format;
- aRb.result->pixelSize = aRb.pixelSize;
- aRb.result->data.resize(aRb.bufSize);
+ for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
+ const QRhiD3D11::TextureReadback &readback(activeTextureReadbacks[i]);
+ readback.result->format = readback.format;
+ readback.result->pixelSize = readback.pixelSize;
D3D11_MAPPED_SUBRESOURCE mp;
- HRESULT hr = context->Map(aRb.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
- if (FAILED(hr)) {
+ HRESULT hr = context->Map(readback.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
+ if (SUCCEEDED(hr)) {
+ readback.result->data.resize(int(readback.byteSize));
+ // nothing says the rows are tightly packed in the texture, must take
+ // the stride into account
+ char *dst = readback.result->data.data();
+ char *src = static_cast<char *>(mp.pData);
+ for (int y = 0, h = readback.pixelSize.height(); y != h; ++y) {
+ memcpy(dst, src, readback.bpl);
+ dst += readback.bpl;
+ src += mp.RowPitch;
+ }
+ context->Unmap(readback.stagingTex, 0);
+ } else {
qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
- aRb.stagingTex->Release();
- continue;
}
- // nothing says the rows are tightly packed in the texture, must take
- // the stride into account
- char *dst = aRb.result->data.data();
- char *src = static_cast<char *>(mp.pData);
- for (int y = 0, h = aRb.pixelSize.height(); y != h; ++y) {
- memcpy(dst, src, aRb.bpl);
- dst += aRb.bpl;
- src += mp.RowPitch;
+
+ readback.stagingTex->Release();
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingTex))));
+
+ if (readback.result->completed)
+ completedCallbacks.append(readback.result->completed);
+
+ activeTextureReadbacks.removeAt(i);
+ }
+
+ for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
+ const QRhiD3D11::BufferReadback &readback(activeBufferReadbacks[i]);
+
+ D3D11_MAPPED_SUBRESOURCE mp;
+ HRESULT hr = context->Map(readback.stagingBuf, 0, D3D11_MAP_READ, 0, &mp);
+ if (SUCCEEDED(hr)) {
+ readback.result->data.resize(int(readback.byteSize));
+ memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
+ context->Unmap(readback.stagingBuf, 0);
+ } else {
+ qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
}
- context->Unmap(aRb.stagingTex, 0);
- aRb.stagingTex->Release();
- QRHI_PROF_F(releaseReadbackBuffer(quint64(quintptr(aRb.stagingTex))));
+ readback.stagingBuf->Release();
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingBuf))));
- if (aRb.result->completed)
- completedCallbacks.append(aRb.result->completed);
+ if (readback.result->completed)
+ completedCallbacks.append(readback.result->completed);
- activeReadbacks.removeAt(i);
+ activeBufferReadbacks.removeAt(i);
}
for (auto f : completedCallbacks)
@@ -1509,10 +1657,10 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
if (rtD->dsAttCount && wantsDsClear)
clearCmd.args.clear.mask |= QD3D11CommandBuffer::Command::Depth | QD3D11CommandBuffer::Command::Stencil;
- clearCmd.args.clear.c[0] = colorClearValue.redF();
- clearCmd.args.clear.c[1] = colorClearValue.greenF();
- clearCmd.args.clear.c[2] = colorClearValue.blueF();
- clearCmd.args.clear.c[3] = colorClearValue.alphaF();
+ clearCmd.args.clear.c[0] = float(colorClearValue.redF());
+ clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
+ clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
+ clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
cbD->commands.append(clearCmd);
@@ -1530,9 +1678,10 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, cbD->currentTarget);
- const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
- for (int att = 0, attCount = colorAttachments.count(); att != attCount; ++att) {
- const QRhiColorAttachment &colorAtt(colorAttachments[att]);
+ for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
+ it != itEnd; ++it)
+ {
+ const QRhiColorAttachment &colorAtt(*it);
if (!colorAtt.resolveTexture())
continue;
@@ -1543,8 +1692,8 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::ResolveSubRes;
cmd.args.resolveSubRes.dst = dstTexD->tex;
- cmd.args.resolveSubRes.dstSubRes = D3D11CalcSubresource(colorAtt.resolveLevel(),
- colorAtt.resolveLayer(),
+ cmd.args.resolveSubRes.dstSubRes = D3D11CalcSubresource(UINT(colorAtt.resolveLevel()),
+ UINT(colorAtt.resolveLayer()),
dstTexD->mipLevelCount);
if (srcTexD) {
cmd.args.resolveSubRes.src = srcTexD->tex;
@@ -1571,7 +1720,7 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
continue;
}
}
- cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, colorAtt.layer(), 1);
+ cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
cbD->commands.append(cmd);
}
@@ -1638,9 +1787,9 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::Dispatch;
- cmd.args.dispatch.x = x;
- cmd.args.dispatch.y = y;
- cmd.args.dispatch.z = z;
+ cmd.args.dispatch.x = UINT(x);
+ cmd.args.dispatch.y = UINT(y);
+ cmd.args.dispatch.z = UINT(z);
cbD->commands.append(cmd);
}
@@ -1670,7 +1819,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
srbD->csUAVs.clear();
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -1682,11 +1831,11 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
// dynamic ubuf offsets are not considered here, those are baked in
// at a later stage, which is good as vsubufoffsets and friends are
// per-srb, not per-setShaderResources call
- const uint offsetInConstants = b->u.ubuf.offset / 16;
+ const uint offsetInConstants = uint(b->u.ubuf.offset) / 16;
// size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
// We can round up if needed since the buffers's actual size
// (ByteWidth) is always a multiple of 256.
- const uint sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16;
+ const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
srbD->vsubufs.feed(b->binding, bufD->buffer);
srbD->vsubufoffsets.feed(b->binding, offsetInConstants);
@@ -1804,7 +1953,7 @@ void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD)
D3D11_MAPPED_SUBRESOURCE mp;
HRESULT hr = context->Map(bufD->buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mp);
if (SUCCEEDED(hr)) {
- memcpy(mp.pData, bufD->dynBuf.constData(), bufD->dynBuf.size());
+ memcpy(mp.pData, bufD->dynBuf.constData(), size_t(bufD->dynBuf.size()));
context->Unmap(bufD->buffer, 0);
} else {
qWarning("Failed to map buffer: %s", qPrintable(comErrorMessage(hr)));
@@ -1817,13 +1966,13 @@ static void applyDynamicOffsets(QVarLengthArray<UINT, 4> *offsets,
QRhiBatchedBindings<UINT> *ubufoffsets,
const uint *dynOfsPairs, int dynOfsPairCount)
{
- const UINT count = ubufs->batches[batchIndex].resources.count();
+ const int count = ubufs->batches[batchIndex].resources.count();
const UINT startBinding = ubufs->batches[batchIndex].startBinding;
*offsets = ubufoffsets->batches[batchIndex].resources;
- for (UINT b = 0; b < count; ++b) {
+ for (int b = 0; b < count; ++b) {
for (int di = 0; di < dynOfsPairCount; ++di) {
const uint binding = dynOfsPairs[2 * di];
- if (binding == startBinding + b) {
+ if (binding == startBinding + UINT(b)) {
const uint offsetInConstants = dynOfsPairs[2 * di + 1];
(*offsets)[b] = offsetInConstants;
break;
@@ -1838,37 +1987,37 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
{
if (!offsetOnlyChange) {
for (const auto &batch : srbD->vssamplers.batches)
- context->VSSetSamplers(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->VSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
for (const auto &batch : srbD->vsshaderresources.batches) {
- context->VSSetShaderResources(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->VSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
contextState.vsHighestActiveSrvBinding = qMax<int>(contextState.vsHighestActiveSrvBinding,
- batch.startBinding + batch.resources.count() - 1);
+ int(batch.startBinding) + batch.resources.count() - 1);
}
for (const auto &batch : srbD->fssamplers.batches)
- context->PSSetSamplers(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->PSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
for (const auto &batch : srbD->fsshaderresources.batches) {
- context->PSSetShaderResources(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->PSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
contextState.fsHighestActiveSrvBinding = qMax<int>(contextState.fsHighestActiveSrvBinding,
- batch.startBinding + batch.resources.count() - 1);
+ int(batch.startBinding) + batch.resources.count() - 1);
}
for (const auto &batch : srbD->cssamplers.batches)
- context->CSSetSamplers(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->CSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
for (const auto &batch : srbD->csshaderresources.batches) {
- context->CSSetShaderResources(batch.startBinding, batch.resources.count(), batch.resources.constData());
+ context->CSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
contextState.csHighestActiveSrvBinding = qMax<int>(contextState.csHighestActiveSrvBinding,
- batch.startBinding + batch.resources.count() - 1);
+ int(batch.startBinding) + batch.resources.count() - 1);
}
}
for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) {
if (!dynOfsPairCount) {
context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- srbD->vsubufs.batches[i].resources.count(),
+ UINT(srbD->vsubufs.batches[i].resources.count()),
srbD->vsubufs.batches[i].resources.constData(),
srbD->vsubufoffsets.batches[i].resources.constData(),
srbD->vsubufsizes.batches[i].resources.constData());
@@ -1876,7 +2025,7 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
QVarLengthArray<UINT, 4> offsets;
applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount);
context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- srbD->vsubufs.batches[i].resources.count(),
+ UINT(srbD->vsubufs.batches[i].resources.count()),
srbD->vsubufs.batches[i].resources.constData(),
offsets.constData(),
srbD->vsubufsizes.batches[i].resources.constData());
@@ -1886,7 +2035,7 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
for (int i = 0, ie = srbD->fsubufs.batches.count(); i != ie; ++i) {
if (!dynOfsPairCount) {
context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- srbD->fsubufs.batches[i].resources.count(),
+ UINT(srbD->fsubufs.batches[i].resources.count()),
srbD->fsubufs.batches[i].resources.constData(),
srbD->fsubufoffsets.batches[i].resources.constData(),
srbD->fsubufsizes.batches[i].resources.constData());
@@ -1894,7 +2043,7 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
QVarLengthArray<UINT, 4> offsets;
applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount);
context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- srbD->fsubufs.batches[i].resources.count(),
+ UINT(srbD->fsubufs.batches[i].resources.count()),
srbD->fsubufs.batches[i].resources.constData(),
offsets.constData(),
srbD->fsubufsizes.batches[i].resources.constData());
@@ -1904,7 +2053,7 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) {
if (!dynOfsPairCount) {
context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- srbD->csubufs.batches[i].resources.count(),
+ UINT(srbD->csubufs.batches[i].resources.count()),
srbD->csubufs.batches[i].resources.constData(),
srbD->csubufoffsets.batches[i].resources.constData(),
srbD->csubufsizes.batches[i].resources.constData());
@@ -1912,7 +2061,7 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
QVarLengthArray<UINT, 4> offsets;
applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount);
context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- srbD->csubufs.batches[i].resources.count(),
+ UINT(srbD->csubufs.batches[i].resources.count()),
srbD->csubufs.batches[i].resources.constData(),
offsets.constData(),
srbD->csubufsizes.batches[i].resources.constData());
@@ -1921,13 +2070,13 @@ void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
for (int i = 0, ie = srbD->csUAVs.batches.count(); i != ie; ++i) {
const uint startBinding = srbD->csUAVs.batches[i].startBinding;
- const uint count = srbD->csUAVs.batches[i].resources.count();
+ const uint count = uint(srbD->csUAVs.batches[i].resources.count());
context->CSSetUnorderedAccessViews(startBinding,
count,
srbD->csUAVs.batches[i].resources.constData(),
nullptr);
contextState.csHighestActiveUavBinding = qMax<int>(contextState.csHighestActiveUavBinding,
- startBinding + count - 1);
+ int(startBinding + count - 1));
}
}
@@ -1951,7 +2100,7 @@ void QRhiD3D11::resetShaderResources()
QVarLengthArray<UINT, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> nulloffsets(count);
for (int i = 0; i < count; ++i)
nulloffsets[i] = 0;
- context->IASetVertexBuffers(0, count, nullbufs.constData(), nullstrides.constData(), nulloffsets.constData());
+ context->IASetVertexBuffers(0, UINT(count), nullbufs.constData(), nullstrides.constData(), nulloffsets.constData());
contextState.vsHighestActiveVertexBufferBinding = -1;
}
@@ -1964,15 +2113,15 @@ void QRhiD3D11::resetShaderResources()
for (int i = 0; i < nullsrvs.count(); ++i)
nullsrvs[i] = nullptr;
if (contextState.vsHighestActiveSrvBinding >= 0) {
- context->VSSetShaderResources(0, contextState.vsHighestActiveSrvBinding + 1, nullsrvs.constData());
+ context->VSSetShaderResources(0, UINT(contextState.vsHighestActiveSrvBinding + 1), nullsrvs.constData());
contextState.vsHighestActiveSrvBinding = -1;
}
if (contextState.fsHighestActiveSrvBinding >= 0) {
- context->PSSetShaderResources(0, contextState.fsHighestActiveSrvBinding + 1, nullsrvs.constData());
+ context->PSSetShaderResources(0, UINT(contextState.fsHighestActiveSrvBinding + 1), nullsrvs.constData());
contextState.fsHighestActiveSrvBinding = -1;
}
if (contextState.csHighestActiveSrvBinding >= 0) {
- context->CSSetShaderResources(0, contextState.csHighestActiveSrvBinding + 1, nullsrvs.constData());
+ context->CSSetShaderResources(0, UINT(contextState.csHighestActiveSrvBinding + 1), nullsrvs.constData());
contextState.csHighestActiveSrvBinding = -1;
}
}
@@ -1983,7 +2132,7 @@ void QRhiD3D11::resetShaderResources()
D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT> nulluavs(nulluavCount);
for (int i = 0; i < nulluavCount; ++i)
nulluavs[i] = nullptr;
- context->CSSetUnorderedAccessViews(0, nulluavCount, nulluavs.constData(), nullptr);
+ context->CSSetUnorderedAccessViews(0, UINT(nulluavCount), nulluavs.constData(), nullptr);
contextState.csHighestActiveUavBinding = -1;
}
}
@@ -2005,7 +2154,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
// writing the first timestamp only afterwards.
context->Begin(tsDisjoint);
QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->rt);
- context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
+ context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
context->End(tsStart); // just record a timestamp, no Begin needed
}
}
@@ -2018,7 +2167,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
case QD3D11CommandBuffer::Command::SetRenderTarget:
{
QD3D11RenderTargetData *rtD = rtData(cmd.args.setRenderTarget.rt);
- context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
+ context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
}
break;
case QD3D11CommandBuffer::Command::Clear:
@@ -2034,7 +2183,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
if (cmd.args.clear.mask & QD3D11CommandBuffer::Command::Stencil)
ds |= D3D11_CLEAR_STENCIL;
if (ds)
- context->ClearDepthStencilView(rtD->dsv, ds, cmd.args.clear.d, cmd.args.clear.s);
+ context->ClearDepthStencilView(rtD->dsv, ds, cmd.args.clear.d, UINT8(cmd.args.clear.s));
}
break;
case QD3D11CommandBuffer::Command::Viewport:
@@ -2064,8 +2213,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
contextState.vsHighestActiveVertexBufferBinding = qMax<int>(
contextState.vsHighestActiveVertexBufferBinding,
cmd.args.bindVertexBuffers.startSlot + cmd.args.bindVertexBuffers.slotCount - 1);
- context->IASetVertexBuffers(cmd.args.bindVertexBuffers.startSlot,
- cmd.args.bindVertexBuffers.slotCount,
+ context->IASetVertexBuffers(UINT(cmd.args.bindVertexBuffers.startSlot),
+ UINT(cmd.args.bindVertexBuffers.slotCount),
cmd.args.bindVertexBuffers.buffers,
cmd.args.bindVertexBuffers.strides,
cmd.args.bindVertexBuffers.offsets);
@@ -2208,7 +2357,7 @@ static inline uint toD3DBufferUsage(QRhiBuffer::UsageFlags usage)
u |= D3D11_BIND_CONSTANT_BUFFER;
if (usage.testFlag(QRhiBuffer::StorageBuffer))
u |= D3D11_BIND_UNORDERED_ACCESS;
- return u;
+ return uint(u);
}
bool QD3D11Buffer::build()
@@ -2231,7 +2380,7 @@ bool QD3D11Buffer::build()
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.ByteWidth = roundedSize;
+ desc.ByteWidth = UINT(roundedSize);
desc.Usage = m_type == Dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
desc.BindFlags = toD3DBufferUsage(m_usage);
desc.CPUAccessFlags = m_type == Dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
@@ -2250,10 +2399,10 @@ bool QD3D11Buffer::build()
}
if (!m_objectName.isEmpty())
- buffer->SetPrivateData(WKPDID_D3DDebugObjectName, m_objectName.size(), m_objectName.constData());
+ buffer->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
QRHI_PROF;
- QRHI_PROF_F(newBuffer(this, roundedSize, m_type == Dynamic ? 2 : 1, m_type == Dynamic ? 1 : 0));
+ QRHI_PROF_F(newBuffer(this, quint32(roundedSize), m_type == Dynamic ? 2 : 1, m_type == Dynamic ? 1 : 0));
generation += 1;
rhiD->registerResource(this);
@@ -2271,7 +2420,7 @@ ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView()
desc.Format = DXGI_FORMAT_R32_TYPELESS;
desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
desc.Buffer.FirstElement = 0;
- desc.Buffer.NumElements = aligned(m_size, 4) / 4;
+ desc.Buffer.NumElements = UINT(aligned(m_size, 4) / 4);
desc.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_RAW;
QRHI_RES_RHI(QRhiD3D11);
@@ -2332,8 +2481,8 @@ bool QD3D11RenderBuffer::build()
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.Width = m_pixelSize.width();
- desc.Height = m_pixelSize.height();
+ desc.Width = UINT(m_pixelSize.width());
+ desc.Height = UINT(m_pixelSize.height());
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc = sampleDesc;
@@ -2382,10 +2531,10 @@ bool QD3D11RenderBuffer::build()
}
if (!m_objectName.isEmpty())
- tex->SetPrivateData(WKPDID_D3DDebugObjectName, m_objectName.size(), m_objectName.constData());
+ tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
QRHI_PROF;
- QRHI_PROF_F(newRenderBuffer(this, false, false, sampleDesc.Count));
+ QRHI_PROF_F(newRenderBuffer(this, false, false, int(sampleDesc.Count)));
rhiD->registerResource(this);
return true;
@@ -2475,7 +2624,7 @@ bool QD3D11Texture::prepareBuild(QSize *adjustedSize)
QRHI_RES_RHI(QRhiD3D11);
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
- mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
+ mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
if (sampleDesc.Count > 1) {
if (isCube) {
@@ -2561,8 +2710,8 @@ bool QD3D11Texture::build()
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.Width = size.width();
- desc.Height = size.height();
+ desc.Width = UINT(size.width());
+ desc.Height = UINT(size.height());
desc.MipLevels = mipLevelCount;
desc.ArraySize = isCube ? 6 : 1;
desc.Format = dxgiFormat;
@@ -2582,10 +2731,10 @@ bool QD3D11Texture::build()
return false;
if (!m_objectName.isEmpty())
- tex->SetPrivateData(WKPDID_D3DDebugObjectName, m_objectName.size(), m_objectName.constData());
+ tex->SetPrivateData(WKPDID_D3DDebugObjectName, UINT(m_objectName.size()), m_objectName.constData());
QRHI_PROF;
- QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, sampleDesc.Count));
+ QRHI_PROF_F(newTexture(this, true, int(mipLevelCount), isCube ? 6 : 1, int(sampleDesc.Count)));
owns = true;
rhiD->registerResource(this);
@@ -2607,7 +2756,7 @@ bool QD3D11Texture::buildFrom(const QRhiNativeHandles *src)
return false;
QRHI_PROF;
- QRHI_PROF_F(newTexture(this, false, mipLevelCount, m_flags.testFlag(CubeMap) ? 6 : 1, sampleDesc.Count));
+ QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, int(sampleDesc.Count)));
owns = false;
QRHI_RES_RHI(QRhiD3D11);
@@ -2631,12 +2780,12 @@ ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
desc.Format = dxgiFormat;
if (isCube) {
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
- desc.Texture2DArray.MipSlice = level;
+ desc.Texture2DArray.MipSlice = UINT(level);
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.ArraySize = 6;
} else {
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D;
- desc.Texture2D.MipSlice = level;
+ desc.Texture2D.MipSlice = UINT(level);
}
QRHI_RES_RHI(QRhiD3D11);
@@ -2877,17 +3026,20 @@ bool QD3D11TextureRenderTarget::build()
if (rtv[0] || dsv)
release();
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
- Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture());
+ const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
+ Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
QRHI_RES_RHI(QRhiD3D11);
- d.colorAttCount = colorAttachments.count();
- for (int i = 0; i < d.colorAttCount; ++i) {
- QRhiTexture *texture = colorAttachments[i].texture();
- QRhiRenderBuffer *rb = colorAttachments[i].renderBuffer();
+ d.colorAttCount = 0;
+ int attIndex = 0;
+ for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
+ d.colorAttCount += 1;
+ const QRhiColorAttachment &colorAtt(*it);
+ QRhiTexture *texture = colorAtt.texture();
+ QRhiRenderBuffer *rb = colorAtt.renderBuffer();
Q_ASSERT(texture || rb);
if (texture) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, texture);
@@ -2896,34 +3048,34 @@ bool QD3D11TextureRenderTarget::build()
rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
- rtvDesc.Texture2DArray.MipSlice = colorAttachments[i].level();
- rtvDesc.Texture2DArray.FirstArraySlice = colorAttachments[i].layer();
+ rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
+ rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
rtvDesc.Texture2DArray.ArraySize = 1;
} else {
if (texD->sampleDesc.Count > 1) {
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
} else {
rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
- rtvDesc.Texture2D.MipSlice = colorAttachments[i].level();
+ rtvDesc.Texture2D.MipSlice = UINT(colorAtt.level());
}
}
- HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->tex, &rtvDesc, &rtv[i]);
+ HRESULT hr = rhiD->dev->CreateRenderTargetView(texD->tex, &rtvDesc, &rtv[attIndex]);
if (FAILED(hr)) {
qWarning("Failed to create rtv: %s", qPrintable(comErrorMessage(hr)));
return false;
}
- ownsRtv[i] = true;
- if (i == 0) {
+ ownsRtv[attIndex] = true;
+ if (attIndex == 0) {
d.pixelSize = texD->pixelSize();
- d.sampleCount = texD->sampleDesc.Count;
+ d.sampleCount = int(texD->sampleDesc.Count);
}
} else if (rb) {
QD3D11RenderBuffer *rbD = QRHI_RES(QD3D11RenderBuffer, rb);
- ownsRtv[i] = false;
- rtv[i] = rbD->rtv;
- if (i == 0) {
+ ownsRtv[attIndex] = false;
+ rtv[attIndex] = rbD->rtv;
+ if (attIndex == 0) {
d.pixelSize = rbD->pixelSize();
- d.sampleCount = rbD->sampleDesc.Count;
+ d.sampleCount = int(rbD->sampleDesc.Count);
}
}
}
@@ -2945,7 +3097,7 @@ bool QD3D11TextureRenderTarget::build()
}
if (d.colorAttCount == 0) {
d.pixelSize = depthTexD->pixelSize();
- d.sampleCount = depthTexD->sampleDesc.Count;
+ d.sampleCount = int(depthTexD->sampleDesc.Count);
}
} else {
ownsDsv = false;
@@ -2953,7 +3105,7 @@ bool QD3D11TextureRenderTarget::build()
dsv = depthRbD->dsv;
if (d.colorAttCount == 0) {
d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
- d.sampleCount = depthRbD->sampleDesc.Count;
+ d.sampleCount = int(depthRbD->sampleDesc.Count);
}
}
d.dsAttCount = 1;
@@ -3006,11 +3158,11 @@ bool QD3D11ShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
- sortedBindings = m_bindings;
+ std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
- return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
+ return a.data()->binding < b.data()->binding;
});
boundResourceData.resize(sortedBindings.count());
@@ -3177,9 +3329,9 @@ static inline D3D11_PRIMITIVE_TOPOLOGY toD3DTopology(QRhiGraphicsPipeline::Topol
}
}
-static inline uint toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
+static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
{
- uint f = 0;
+ UINT8 f = 0;
if (c.testFlag(QRhiGraphicsPipeline::R))
f |= D3D11_COLOR_WRITE_ENABLE_RED;
if (c.testFlag(QRhiGraphicsPipeline::G))
@@ -3314,22 +3466,22 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
ID3DBlob *bytecode = nullptr;
ID3DBlob *errors = nullptr;
- HRESULT hr = d3dCompile(hlslSource.shader().constData(), hlslSource.shader().size(),
+ HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
nullptr, nullptr, nullptr,
hlslSource.entryPoint().constData(), target, 0, 0, &bytecode, &errors);
if (FAILED(hr) || !bytecode) {
qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
if (errors) {
*error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
- errors->GetBufferSize());
+ int(errors->GetBufferSize()));
errors->Release();
}
return QByteArray();
}
QByteArray result;
- result.resize(bytecode->GetBufferSize());
- memcpy(result.data(), bytecode->GetBufferPointer(), result.size());
+ result.resize(int(bytecode->GetBufferSize()));
+ memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
bytecode->Release();
return result;
}
@@ -3340,6 +3492,8 @@ bool QD3D11GraphicsPipeline::build()
release();
QRHI_RES_RHI(QRhiD3D11);
+ if (!rhiD->sanityCheckGraphicsPipeline(this))
+ return false;
D3D11_RASTERIZER_DESC rastDesc;
memset(&rastDesc, 0, sizeof(rastDesc));
@@ -3361,8 +3515,8 @@ bool QD3D11GraphicsPipeline::build()
dsDesc.DepthFunc = toD3DCompareOp(m_depthOp);
dsDesc.StencilEnable = m_stencilTest;
if (m_stencilTest) {
- dsDesc.StencilReadMask = m_stencilReadMask;
- dsDesc.StencilWriteMask = m_stencilWriteMask;
+ dsDesc.StencilReadMask = UINT8(m_stencilReadMask);
+ dsDesc.StencilWriteMask = UINT8(m_stencilWriteMask);
dsDesc.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
dsDesc.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
dsDesc.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
@@ -3409,58 +3563,86 @@ bool QD3D11GraphicsPipeline::build()
QByteArray vsByteCode;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
- QString error;
- QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
- if (bytecode.isEmpty()) {
- qWarning("HLSL shader compilation failed: %s", qPrintable(error));
- return false;
- }
- switch (shaderStage.type()) {
- case QRhiShaderStage::Vertex:
- hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs);
- if (FAILED(hr)) {
- qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
- return false;
+ auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
+ if (cacheIt != rhiD->m_shaderCache.constEnd()) {
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ vs = static_cast<ID3D11VertexShader *>(cacheIt->s);
+ vs->AddRef();
+ vsByteCode = cacheIt->bytecode;
+ break;
+ case QRhiShaderStage::Fragment:
+ fs = static_cast<ID3D11PixelShader *>(cacheIt->s);
+ fs->AddRef();
+ break;
+ default:
+ break;
}
- vsByteCode = bytecode;
- break;
- case QRhiShaderStage::Fragment:
- hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs);
- if (FAILED(hr)) {
- qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
+ } else {
+ QString error;
+ const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
+ if (bytecode.isEmpty()) {
+ qWarning("HLSL shader compilation failed: %s", qPrintable(error));
return false;
}
- break;
- default:
- break;
+
+ if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) {
+ // Use the simplest strategy: too many cached shaders -> drop them all.
+ rhiD->clearShaderCache();
+ }
+
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs);
+ if (FAILED(hr)) {
+ qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+ vsByteCode = bytecode;
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode));
+ vs->AddRef();
+ break;
+ case QRhiShaderStage::Fragment:
+ hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs);
+ if (FAILED(hr)) {
+ qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode));
+ fs->AddRef();
+ break;
+ default:
+ break;
+ }
}
}
d3dTopology = toD3DTopology(m_topology);
if (!vsByteCode.isEmpty()) {
- const QVector<QRhiVertexInputBinding> bindings = m_vertexInputLayout.bindings();
- const QVector<QRhiVertexInputAttribute> attributes = m_vertexInputLayout.attributes();
QVarLengthArray<D3D11_INPUT_ELEMENT_DESC, 4> inputDescs;
- for (const QRhiVertexInputAttribute &attribute : attributes) {
+ for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
+ it != itEnd; ++it)
+ {
D3D11_INPUT_ELEMENT_DESC desc;
memset(&desc, 0, sizeof(desc));
// the output from SPIRV-Cross uses TEXCOORD<location> as the semantic
desc.SemanticName = "TEXCOORD";
- desc.SemanticIndex = attribute.location();
- desc.Format = toD3DAttributeFormat(attribute.format());
- desc.InputSlot = attribute.binding();
- desc.AlignedByteOffset = attribute.offset();
- const QRhiVertexInputBinding &binding(bindings[attribute.binding()]);
- if (binding.classification() == QRhiVertexInputBinding::PerInstance) {
+ desc.SemanticIndex = UINT(it->location());
+ desc.Format = toD3DAttributeFormat(it->format());
+ desc.InputSlot = UINT(it->binding());
+ desc.AlignedByteOffset = it->offset();
+ const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
+ if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
desc.InputSlotClass = D3D11_INPUT_PER_INSTANCE_DATA;
- desc.InstanceDataStepRate = binding.instanceStepRate();
+ desc.InstanceDataStepRate = UINT(inputBinding->instanceStepRate());
} else {
desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
}
inputDescs.append(desc);
}
- hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), inputDescs.count(), vsByteCode, vsByteCode.size(), &inputLayout);
+ hr = rhiD->dev->CreateInputLayout(inputDescs.constData(), UINT(inputDescs.count()),
+ vsByteCode, SIZE_T(vsByteCode.size()), &inputLayout);
if (FAILED(hr)) {
qWarning("Failed to create input layout: %s", qPrintable(comErrorMessage(hr)));
return false;
@@ -3502,19 +3684,31 @@ bool QD3D11ComputePipeline::build()
QRHI_RES_RHI(QRhiD3D11);
- QString error;
- QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
- if (bytecode.isEmpty()) {
- qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
- return false;
- }
+ auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
+ if (cacheIt != rhiD->m_shaderCache.constEnd()) {
+ cs = static_cast<ID3D11ComputeShader *>(cacheIt->s);
+ } else {
+ QString error;
+ const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
+ if (bytecode.isEmpty()) {
+ qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
+ return false;
+ }
- HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs);
- if (FAILED(hr)) {
- qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
- return false;
+ HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs);
+ if (FAILED(hr)) {
+ qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
+ return false;
+ }
+
+ if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
+ rhiD->clearShaderCache();
+
+ rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode));
}
+ cs->AddRef();
+
generation += 1;
rhiD->registerResource(this);
return true;
@@ -3637,8 +3831,8 @@ bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI
{
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.Width = size.width();
- desc.Height = size.height();
+ desc.Width = UINT(size.width());
+ desc.Height = UINT(size.height());
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = format;
@@ -3694,11 +3888,23 @@ bool QD3D11SwapChain::buildOrResize()
const UINT swapChainFlags = 0;
QRHI_RES_RHI(QRhiD3D11);
- const bool useFlipDiscard = rhiD->hasDxgi2 && rhiD->supportsFlipDiscardSwapchain;
+ bool useFlipDiscard = rhiD->hasDxgi2 && rhiD->supportsFlipDiscardSwapchain;
if (!swapChain) {
HWND hwnd = reinterpret_cast<HWND>(window->winId());
sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ // Take a shortcut for alpha: our QWindow is OpenGLSurface so whatever
+ // the platform plugin does to enable transparency for OpenGL window
+ // will be sufficient for us too on the legacy (DISCARD) path. For
+ // FLIP_DISCARD we'd need to use DirectComposition (create a
+ // IDCompositionDevice/Target/Visual), avoid that for now.
+ if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
+ useFlipDiscard = false;
+ if (window->requestedFormat().alphaBufferSize() <= 0)
+ qWarning("Swapchain says surface has alpha but the window has no alphaBufferSize set. "
+ "This may lead to problems.");
+ }
+
HRESULT hr;
if (useFlipDiscard) {
// We use FLIP_DISCARD which implies a buffer count of 2 (as opposed to the
@@ -3709,18 +3915,17 @@ bool QD3D11SwapChain::buildOrResize()
DXGI_SWAP_CHAIN_DESC1 desc;
memset(&desc, 0, sizeof(desc));
- desc.Width = pixelSize.width();
- desc.Height = pixelSize.height();
+ desc.Width = UINT(pixelSize.width());
+ desc.Height = UINT(pixelSize.height());
desc.Format = colorFormat;
desc.SampleDesc.Count = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = BUFFER_COUNT;
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
- if (m_flags.testFlag(SurfaceHasPreMulAlpha))
- desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
- else if (m_flags.testFlag(SurfaceHasNonPreMulAlpha))
- desc.AlphaMode = DXGI_ALPHA_MODE_STRAIGHT;
+ // Do not bother with AlphaMode, if won't work unless we go through
+ // DirectComposition. Instead, we just take the other (DISCARD)
+ // path for now when alpha is requested.
desc.Flags = swapChainFlags;
IDXGISwapChain1 *sc1;
@@ -3735,8 +3940,8 @@ bool QD3D11SwapChain::buildOrResize()
DXGI_SWAP_CHAIN_DESC desc;
memset(&desc, 0, sizeof(desc));
- desc.BufferDesc.Width = pixelSize.width();
- desc.BufferDesc.Height = pixelSize.height();
+ desc.BufferDesc.Width = UINT(pixelSize.width());
+ desc.BufferDesc.Height = UINT(pixelSize.height());
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1;
desc.BufferDesc.Format = colorFormat;
@@ -3758,9 +3963,13 @@ bool QD3D11SwapChain::buildOrResize()
} else {
releaseBuffers();
const UINT count = useFlipDiscard ? BUFFER_COUNT : 1;
- HRESULT hr = swapChain->ResizeBuffers(count, pixelSize.width(), pixelSize.height(),
+ HRESULT hr = swapChain->ResizeBuffers(count, UINT(pixelSize.width()), UINT(pixelSize.height()),
colorFormat, swapChainFlags);
- if (FAILED(hr)) {
+ if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
+ qWarning("Device loss detected in ResizeBuffers()");
+ rhiD->deviceLost = true;
+ return false;
+ } else if (FAILED(hr)) {
qWarning("Failed to resize D3D11 swapchain: %s", qPrintable(comErrorMessage(hr)));
return false;
}
@@ -3808,9 +4017,16 @@ bool QD3D11SwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
- qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
- m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
- pixelSize.width(), pixelSize.height());
+ if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
+ m_depthStencil->setPixelSize(pixelSize);
+ if (!m_depthStencil->build())
+ qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
+ pixelSize.width(), pixelSize.height());
+ } else {
+ qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
+ m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
+ pixelSize.width(), pixelSize.height());
+ }
}
currentFrameSlot = 0;
@@ -3821,13 +4037,13 @@ bool QD3D11SwapChain::buildOrResize()
QD3D11ReferenceRenderTarget *rtD = QRHI_RES(QD3D11ReferenceRenderTarget, &rt);
rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
rtD->d.pixelSize = pixelSize;
- rtD->d.dpr = window->devicePixelRatio();
- rtD->d.sampleCount = sampleDesc.Count;
+ rtD->d.dpr = float(window->devicePixelRatio());
+ rtD->d.sampleCount = int(sampleDesc.Count);
rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
QRHI_PROF;
- QRHI_PROF_F(resizeSwapChain(this, BUFFER_COUNT, sampleDesc.Count > 1 ? BUFFER_COUNT : 0, sampleDesc.Count));
+ QRHI_PROF_F(resizeSwapChain(this, BUFFER_COUNT, sampleDesc.Count > 1 ? BUFFER_COUNT : 0, int(sampleDesc.Count)));
if (rhiP) {
D3D11_QUERY_DESC queryDesc;
memset(&queryDesc, 0, sizeof(queryDesc));
@@ -3861,4 +4077,34 @@ bool QD3D11SwapChain::buildOrResize()
return true;
}
+void QRhiD3D11::DeviceCurse::initResources()
+{
+ framesLeft = framesToActivate;
+
+ HRESULT hr = q->dev->CreateComputeShader(g_killDeviceByTimingOut, sizeof(g_killDeviceByTimingOut), nullptr, &cs);
+ if (FAILED(hr)) {
+ qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
+ return;
+ }
+}
+
+void QRhiD3D11::DeviceCurse::releaseResources()
+{
+ if (cs) {
+ cs->Release();
+ cs = nullptr;
+ }
+}
+
+void QRhiD3D11::DeviceCurse::activate()
+{
+ if (!cs)
+ return;
+
+ qDebug("Activating Curse. Goodbye Cruel World.");
+
+ q->context->CSSetShader(cs, nullptr, 0);
+ q->context->Dispatch(256, 1, 1);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h
index 3e2e492d9c..5df1843b1e 100644
--- a/src/gui/rhi/qrhid3d11_p.h
+++ b/src/gui/rhi/qrhid3d11_p.h
@@ -58,6 +58,9 @@ QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
{
bool enableDebugLayer = false;
+
+ int framesUntilKillingDeviceViaTdr = -1;
+ bool repeatDeviceKill = false;
};
struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 582146315d..26de34ae0a 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
- QVector<QRhiShaderResourceBinding> sortedBindings;
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
@@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
- QVector<BoundResourceData> boundResourceData;
+ QVarLengthArray<BoundResourceData, 8> boundResourceData;
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
QRhiBatchedBindings<UINT> vsubufoffsets;
@@ -631,7 +631,9 @@ public:
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
- void makeThreadLocalNativeContextCurrent() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
@@ -646,6 +648,7 @@ public:
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device);
+ void clearShaderCache();
bool debugLayer = false;
bool importedDevice = false;
@@ -656,6 +659,7 @@ public:
IDXGIFactory1 *dxgiFactory = nullptr;
bool hasDxgi2 = false;
bool supportsFlipDiscardSwapchain = false;
+ bool deviceLost = false;
QRhiD3D11NativeHandles nativeHandlesStruct;
struct {
@@ -674,19 +678,47 @@ public:
QD3D11CommandBuffer cbWrapper;
} ofr;
- struct ActiveReadback {
+ struct TextureReadback {
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
ID3D11Texture2D *stagingTex;
- quint32 bufSize;
+ quint32 byteSize;
quint32 bpl;
QSize pixelSize;
QRhiTexture::Format format;
};
- QVector<ActiveReadback> activeReadbacks;
+ QVector<TextureReadback> activeTextureReadbacks;
+ struct BufferReadback {
+ QRhiBufferReadbackResult *result;
+ quint32 byteSize;
+ ID3D11Buffer *stagingBuf;
+ };
+ QVector<BufferReadback> activeBufferReadbacks;
+
+ struct Shader {
+ Shader() = default;
+ Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { }
+ IUnknown *s;
+ QByteArray bytecode;
+ };
+ QHash<QRhiShaderStage, Shader> m_shaderCache;
+
+ struct DeviceCurse {
+ DeviceCurse(QRhiD3D11 *impl) : q(impl) { }
+ QRhiD3D11 *q;
+ int framesToActivate = -1;
+ bool permanent = false;
+ int framesLeft = 0;
+ ID3D11ComputeShader *cs = nullptr;
+
+ void initResources();
+ void releaseResources();
+ void activate();
+ } deviceCurse;
};
-Q_DECLARE_TYPEINFO(QRhiD3D11::ActiveReadback, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index f4e711e33e..e355979626 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -39,6 +39,7 @@
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtGui/private/qopenglextensions_p.h>
+#include <QtGui/private/qopenglprogrambinarycache_p.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
@@ -275,6 +276,12 @@ QT_BEGIN_NAMESPACE
#define GL_POINT_SPRITE 0x8861
#endif
+#ifndef GL_MAP_READ_BIT
+#define GL_MAP_READ_BIT 0x0001
+#endif
+
+Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
+
/*!
Constructs a new QRhiGles2InitParams.
@@ -371,7 +378,12 @@ bool QRhiGles2::ensureContext(QSurface *surface) const
return true;
if (!ctx->makeCurrent(surface)) {
- qWarning("QRhiGles2: Failed to make context current. Expect bad things to happen.");
+ if (ctx->isValid()) {
+ qWarning("QRhiGles2: Failed to make context current. Expect bad things to happen.");
+ } else {
+ qWarning("QRhiGles2: Context is lost.");
+ contextLost = true;
+ }
return false;
}
@@ -484,6 +496,15 @@ bool QRhiGles2::create(QRhi::Flags flags)
else
caps.textureCompareMode = true;
+ // proper as in ES 3.0 (glMapBufferRange), not the old glMapBuffer
+ // extension(s) (which is not in ES 3.0...messy)
+ caps.properMapBuffer = f->hasOpenGLExtension(QOpenGLExtensions::MapBufferRange);
+
+ if (caps.gles)
+ caps.nonBaseLevelFramebufferTexture = caps.ctxMajor >= 3; // ES 3.0
+ else
+ caps.nonBaseLevelFramebufferTexture = true;
+
if (!caps.gles) {
f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
f->glEnable(GL_POINT_SPRITE);
@@ -491,6 +512,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
nativeHandlesStruct.context = ctx;
+ contextLost = false;
+
return true;
}
@@ -502,6 +525,10 @@ void QRhiGles2::destroy()
ensureContext();
executeDeferredReleases();
+ for (uint shader : m_shaderCache)
+ f->glDeleteShader(shader);
+ m_shaderCache.clear();
+
if (!importedContext) {
delete ctx;
ctx = nullptr;
@@ -572,7 +599,9 @@ QRhiBuffer *QRhiGles2::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlag
int QRhiGles2::ubufAlignment() const
{
- return 256;
+ // No real uniform buffers are used so no need to pretend there is any
+ // alignment requirement.
+ return 1;
}
bool QRhiGles2::isYUpInFramebuffer() const
@@ -650,7 +679,7 @@ static inline GLenum toGlCompressedTextureFormat(QRhiTexture::Format format, QRh
bool QRhiGles2::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
{
if (isCompressedFormat(format))
- return supportedCompressedFormats.contains(toGlCompressedTextureFormat(format, flags));
+ return supportedCompressedFormats.contains(GLint(toGlCompressedTextureFormat(format, flags)));
switch (format) {
case QRhiTexture::D16:
@@ -716,6 +745,12 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return caps.baseVertex;
case QRhi::BaseInstance:
return false; // not in ES 3.2, so won't bother
+ case QRhi::TriangleFanTopology:
+ return true;
+ case QRhi::ReadBackNonUniformBuffer:
+ return !caps.gles || caps.properMapBuffer;
+ case QRhi::ReadBackNonBaseMipLevel:
+ return caps.nonBaseLevelFramebufferTexture;
default:
Q_UNREACHABLE();
return false;
@@ -749,12 +784,28 @@ void QRhiGles2::sendVMemStatsToProfiler()
// nothing to do here
}
-void QRhiGles2::makeThreadLocalNativeContextCurrent()
+bool QRhiGles2::makeThreadLocalNativeContextCurrent()
{
if (inFrame && !ofr.active)
- ensureContext(currentSwapChain->surface);
+ return ensureContext(currentSwapChain->surface);
else
- ensureContext();
+ return ensureContext();
+}
+
+void QRhiGles2::releaseCachedResources()
+{
+ if (!ensureContext())
+ return;
+
+ for (uint shader : m_shaderCache)
+ f->glDeleteShader(shader);
+
+ m_shaderCache.clear();
+}
+
+bool QRhiGles2::isDeviceLost() const
+{
+ return contextLost;
}
QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
@@ -836,7 +887,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
bool hasDynamicOffsetInSrb = false;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
// no BufUniformRead / AccessUniform because no real uniform buffers are used
@@ -915,7 +966,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
uint *p = cmd.args.bindShaderResources.dynamicOffsetPairs;
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
- *p++ = dynOfs.first;
+ *p++ = uint(dynOfs.first);
*p++ = dynOfs.second;
}
} else {
@@ -977,8 +1028,12 @@ void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Viewport;
const std::array<float, 4> r = viewport.viewport();
- cmd.args.viewport.x = qMax(0.0f, r[0]);
- cmd.args.viewport.y = qMax(0.0f, r[1]);
+ // A negative width or height is an error. A negative x or y is not.
+ if (r[2] < 0.0f || r[3] < 0.0f)
+ return;
+
+ cmd.args.viewport.x = r[0];
+ cmd.args.viewport.y = r[1];
cmd.args.viewport.w = r[2];
cmd.args.viewport.h = r[3];
cmd.args.viewport.d0 = viewport.minDepth();
@@ -994,8 +1049,12 @@ void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Scissor;
const std::array<int, 4> r = scissor.scissor();
- cmd.args.scissor.x = qMax(0, r[0]);
- cmd.args.scissor.y = qMax(0, r[1]);
+ // A negative width or height is an error. A negative x or y is not.
+ if (r[2] < 0 || r[3] < 0)
+ return;
+
+ cmd.args.scissor.x = r[0];
+ cmd.args.scissor.y = r[1];
cmd.args.scissor.w = r[2];
cmd.args.scissor.h = r[3];
cbD->commands.append(cmd);
@@ -1008,10 +1067,10 @@ void QRhiGles2::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::BlendConstants;
- cmd.args.blendConstants.r = c.redF();
- cmd.args.blendConstants.g = c.greenF();
- cmd.args.blendConstants.b = c.blueF();
- cmd.args.blendConstants.a = c.alphaF();
+ cmd.args.blendConstants.r = float(c.redF());
+ cmd.args.blendConstants.g = float(c.greenF());
+ cmd.args.blendConstants.b = float(c.blueF());
+ cmd.args.blendConstants.a = float(c.alphaF());
cbD->commands.append(cmd);
}
@@ -1141,7 +1200,7 @@ QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
if (!ensureContext(swapChainD->surface))
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
currentSwapChain = swapChainD;
@@ -1164,7 +1223,7 @@ QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::EndFrame);
if (!ensureContext(swapChainD->surface))
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
executeCommandBuffer(&swapChainD->cb);
@@ -1188,7 +1247,7 @@ QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
{
Q_UNUSED(flags);
if (!ensureContext())
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
ofr.active = true;
@@ -1210,7 +1269,7 @@ QRhi::FrameOpResult QRhiGles2::endOffscreenFrame(QRhi::EndFrameFlags flags)
addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame);
if (!ensureContext())
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
executeCommandBuffer(&ofr.cbWrapper);
@@ -1224,14 +1283,14 @@ QRhi::FrameOpResult QRhiGles2::finish()
Q_ASSERT(!currentSwapChain);
Q_ASSERT(ofr.cbWrapper.recordingPass == QGles2CommandBuffer::NoPass);
if (!ensureContext())
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
executeCommandBuffer(&ofr.cbWrapper);
ofr.cbWrapper.resetCommands();
} else {
Q_ASSERT(currentSwapChain);
Q_ASSERT(currentSwapChain->cb.recordingPass == QGles2CommandBuffer::NoPass);
if (!ensureContext(currentSwapChain->surface))
- return QRhi::FrameOpError;
+ return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
executeCommandBuffer(&currentSwapChain->cb);
currentSwapChain->cb.resetCommands();
}
@@ -1299,7 +1358,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
}
cmd.args.subImage.target = texD->target;
cmd.args.subImage.texture = texD->texture;
- cmd.args.subImage.faceTarget = faceTargetBase + layer;
+ cmd.args.subImage.faceTarget = faceTargetBase + uint(layer);
cmd.args.subImage.level = level;
cmd.args.subImage.dx = dp.x();
cmd.args.subImage.dy = dp.y();
@@ -1318,7 +1377,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.cmd = QGles2CommandBuffer::Command::CompressedSubImage;
cmd.args.compressedSubImage.target = texD->target;
cmd.args.compressedSubImage.texture = texD->texture;
- cmd.args.compressedSubImage.faceTarget = faceTargetBase + layer;
+ cmd.args.compressedSubImage.faceTarget = faceTargetBase + uint(layer);
cmd.args.compressedSubImage.level = level;
cmd.args.compressedSubImage.dx = dp.x();
cmd.args.compressedSubImage.dy = dp.y();
@@ -1333,7 +1392,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.cmd = QGles2CommandBuffer::Command::CompressedImage;
cmd.args.compressedImage.target = texD->target;
cmd.args.compressedImage.texture = texD->texture;
- cmd.args.compressedImage.faceTarget = faceTargetBase + layer;
+ cmd.args.compressedImage.faceTarget = faceTargetBase + uint(layer);
cmd.args.compressedImage.level = level;
cmd.args.compressedImage.glintformat = texD->glintformat;
cmd.args.compressedImage.w = size.width();
@@ -1351,7 +1410,7 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.cmd = QGles2CommandBuffer::Command::SubImage;
cmd.args.subImage.target = texD->target;
cmd.args.subImage.texture = texD->texture;
- cmd.args.subImage.faceTarget = faceTargetBase + layer;
+ cmd.args.subImage.faceTarget = faceTargetBase + uint(layer);
cmd.args.subImage.level = level;
cmd.args.subImage.dx = dp.x();
cmd.args.subImage.dy = dp.y();
@@ -1375,65 +1434,83 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
- QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
- Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
- memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), u.data.size());
- } else {
- trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
- QGles2CommandBuffer::Command cmd;
- cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
- cmd.args.bufferSubData.target = bufD->targetForDataOps;
- cmd.args.bufferSubData.buffer = bufD->buffer;
- cmd.args.bufferSubData.offset = u.offset;
- cmd.args.bufferSubData.size = u.data.size();
- cmd.args.bufferSubData.data = cbD->retainData(u.data);
- cbD->commands.append(cmd);
- }
- }
-
- for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
- QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
- Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
- if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
- memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), u.data.size());
- } else {
- trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
- QGles2CommandBuffer::Command cmd;
- cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
- cmd.args.bufferSubData.target = bufD->targetForDataOps;
- cmd.args.bufferSubData.buffer = bufD->buffer;
- cmd.args.bufferSubData.offset = u.offset;
- cmd.args.bufferSubData.size = u.data.size();
- cmd.args.bufferSubData.data = cbD->retainData(u.data);
- cbD->commands.append(cmd);
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
+ if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
+ QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
+ Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
+ if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
+ memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
+ } else {
+ trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
+ QGles2CommandBuffer::Command cmd;
+ cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
+ cmd.args.bufferSubData.target = bufD->targetForDataOps;
+ cmd.args.bufferSubData.buffer = bufD->buffer;
+ cmd.args.bufferSubData.offset = u.offset;
+ cmd.args.bufferSubData.size = u.data.size();
+ cmd.args.bufferSubData.data = cbD->retainData(u.data);
+ cbD->commands.append(cmd);
+ }
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
+ QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
+ Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
+ if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
+ memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
+ } else {
+ trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
+ QGles2CommandBuffer::Command cmd;
+ cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
+ cmd.args.bufferSubData.target = bufD->targetForDataOps;
+ cmd.args.bufferSubData.buffer = bufD->buffer;
+ cmd.args.bufferSubData.offset = u.offset;
+ cmd.args.bufferSubData.size = u.data.size();
+ cmd.args.bufferSubData.data = cbD->retainData(u.data);
+ cbD->commands.append(cmd);
+ }
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
+ QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
+ if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
+ u.result->data.resize(u.readSize);
+ memcpy(u.result->data.data(), bufD->ubuf.constData() + u.offset, size_t(u.readSize));
+ if (u.result->completed)
+ u.result->completed();
+ } else {
+ QGles2CommandBuffer::Command cmd;
+ cmd.cmd = QGles2CommandBuffer::Command::GetBufferSubData;
+ cmd.args.getBufferSubData.result = u.result;
+ cmd.args.getBufferSubData.target = bufD->targetForDataOps;
+ cmd.args.getBufferSubData.buffer = bufD->buffer;
+ cmd.args.getBufferSubData.offset = u.offset;
+ cmd.args.getBufferSubData.size = u.readSize;
+ cbD->commands.append(cmd);
+ }
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
- QGles2Texture *texD = QRHI_RES(QGles2Texture, u.upload.tex);
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, u.dst);
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
}
}
texD->specified = true;
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
- Q_ASSERT(u.copy.src && u.copy.dst);
- QGles2Texture *srcD = QRHI_RES(QGles2Texture, u.copy.src);
- QGles2Texture *dstD = QRHI_RES(QGles2Texture, u.copy.dst);
+ Q_ASSERT(u.src && u.dst);
+ QGles2Texture *srcD = QRHI_RES(QGles2Texture, u.src);
+ QGles2Texture *dstD = QRHI_RES(QGles2Texture, u.dst);
trackedImageBarrier(cbD, srcD, QGles2Texture::AccessRead);
trackedImageBarrier(cbD, dstD, QGles2Texture::AccessUpdate);
- const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
+ const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
+ const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
// do not translate coordinates, even if sp is bottom-left from gl's pov
- const QPoint sp = u.copy.desc.sourceTopLeft();
- const QPoint dp = u.copy.desc.destinationTopLeft();
+ const QPoint sp = u.desc.sourceTopLeft();
+ const QPoint dp = u.desc.destinationTopLeft();
const GLenum srcFaceTargetBase = srcD->m_flags.testFlag(QRhiTexture::CubeMap)
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : srcD->target;
@@ -1443,42 +1520,44 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::CopyTex;
- cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + u.copy.desc.sourceLayer();
+ cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + uint(u.desc.sourceLayer());
cmd.args.copyTex.srcTexture = srcD->texture;
- cmd.args.copyTex.srcLevel = u.copy.desc.sourceLevel();
+ cmd.args.copyTex.srcLevel = u.desc.sourceLevel();
cmd.args.copyTex.srcX = sp.x();
cmd.args.copyTex.srcY = sp.y();
cmd.args.copyTex.dstTarget = dstD->target;
cmd.args.copyTex.dstTexture = dstD->texture;
- cmd.args.copyTex.dstFaceTarget = dstFaceTargetBase + u.copy.desc.destinationLayer();
- cmd.args.copyTex.dstLevel = u.copy.desc.destinationLevel();
+ cmd.args.copyTex.dstFaceTarget = dstFaceTargetBase + uint(u.desc.destinationLayer());
+ cmd.args.copyTex.dstLevel = u.desc.destinationLevel();
cmd.args.copyTex.dstX = dp.x();
cmd.args.copyTex.dstY = dp.y();
- cmd.args.copyTex.w = size.width();
- cmd.args.copyTex.h = size.height();
+ cmd.args.copyTex.w = copySize.width();
+ cmd.args.copyTex.h = copySize.height();
cbD->commands.append(cmd);
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::ReadPixels;
- cmd.args.readPixels.result = u.read.result;
- QGles2Texture *texD = QRHI_RES(QGles2Texture, u.read.rb.texture());
- trackedImageBarrier(cbD, texD, QGles2Texture::AccessRead);
+ cmd.args.readPixels.result = u.result;
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, u.rb.texture());
+ if (texD)
+ trackedImageBarrier(cbD, texD, QGles2Texture::AccessRead);
cmd.args.readPixels.texture = texD ? texD->texture : 0;
if (texD) {
- cmd.args.readPixels.w = texD->m_pixelSize.width();
- cmd.args.readPixels.h = texD->m_pixelSize.height();
+ const QSize readImageSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
+ cmd.args.readPixels.w = readImageSize.width();
+ cmd.args.readPixels.h = readImageSize.height();
cmd.args.readPixels.format = texD->m_format;
const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap)
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
- cmd.args.readPixels.readTarget = faceTargetBase + u.read.rb.layer();
- cmd.args.readPixels.level = u.read.rb.level();
+ cmd.args.readPixels.readTarget = faceTargetBase + uint(u.rb.layer());
+ cmd.args.readPixels.level = u.rb.level();
}
cbD->commands.append(cmd);
- } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
- QGles2Texture *texD = QRHI_RES(QGles2Texture, u.mipgen.tex);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, u.dst);
trackedImageBarrier(cbD, texD, QGles2Texture::AccessFramebuffer);
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::GenMip;
@@ -1498,6 +1577,8 @@ static inline GLenum toGlTopology(QRhiGraphicsPipeline::Topology t)
return GL_TRIANGLES;
case QRhiGraphicsPipeline::TriangleStrip:
return GL_TRIANGLE_STRIP;
+ case QRhiGraphicsPipeline::TriangleFan:
+ return GL_TRIANGLE_FAN;
case QRhiGraphicsPipeline::Lines:
return GL_LINES;
case QRhiGraphicsPipeline::LineStrip:
@@ -1833,7 +1914,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
f->glBindVertexArray(0);
break;
case QGles2CommandBuffer::Command::Viewport:
- f->glViewport(cmd.args.viewport.x, cmd.args.viewport.y, cmd.args.viewport.w, cmd.args.viewport.h);
+ f->glViewport(GLint(cmd.args.viewport.x), GLint(cmd.args.viewport.y), GLsizei(cmd.args.viewport.w), GLsizei(cmd.args.viewport.h));
f->glDepthRangef(cmd.args.viewport.d0, cmd.args.viewport.d1);
break;
case QGles2CommandBuffer::Command::Scissor:
@@ -1846,8 +1927,8 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.stencilRef.ps);
if (psD) {
- f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), cmd.args.stencilRef.ref, psD->m_stencilReadMask);
- f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), cmd.args.stencilRef.ref, psD->m_stencilReadMask);
+ f->glStencilFuncSeparate(GL_FRONT, toGlCompareOp(psD->m_stencilFront.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask);
+ f->glStencilFuncSeparate(GL_BACK, toGlCompareOp(psD->m_stencilBack.compareOp), GLint(cmd.args.stencilRef.ref), psD->m_stencilReadMask);
} else {
qWarning("No graphics pipeline active for setStencilRef; ignored");
}
@@ -1857,21 +1938,22 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.bindVertexBuffer.ps);
if (psD) {
- const QVector<QRhiVertexInputBinding> bindings = psD->m_vertexInputLayout.bindings();
- const QVector<QRhiVertexInputAttribute> attributes = psD->m_vertexInputLayout.attributes();
- for (const QRhiVertexInputAttribute &a : attributes) {
- const int bindingIdx = a.binding();
+ for (auto it = psD->m_vertexInputLayout.cbeginAttributes(), itEnd = psD->m_vertexInputLayout.cendAttributes();
+ it != itEnd; ++it)
+ {
+ const int bindingIdx = it->binding();
if (bindingIdx != cmd.args.bindVertexBuffer.binding)
continue;
// we do not support more than one vertex buffer
f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer);
- const int stride = bindings[bindingIdx].stride();
+ const QRhiVertexInputBinding *inputBinding = psD->m_vertexInputLayout.bindingAt(bindingIdx);
+ const int stride = int(inputBinding->stride());
int size = 1;
GLenum type = GL_FLOAT;
bool normalize = false;
- switch (a.format()) {
+ switch (it->format()) {
case QRhiVertexInputAttribute::Float4:
type = GL_FLOAT;
size = 4;
@@ -1907,16 +1989,13 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
break;
}
- const int locationIdx = a.location();
- quint32 ofs = a.offset() + cmd.args.bindVertexBuffer.offset;
- f->glVertexAttribPointer(locationIdx, size, type, normalize, stride,
+ const int locationIdx = it->location();
+ quint32 ofs = it->offset() + cmd.args.bindVertexBuffer.offset;
+ f->glVertexAttribPointer(GLuint(locationIdx), size, type, normalize, stride,
reinterpret_cast<const GLvoid *>(quintptr(ofs)));
- f->glEnableVertexAttribArray(locationIdx);
- if (bindings[bindingIdx].classification() == QRhiVertexInputBinding::PerInstance
- && caps.instancing)
- {
- f->glVertexAttribDivisor(locationIdx, bindings[bindingIdx].instanceStepRate());
- }
+ f->glEnableVertexAttribArray(GLuint(locationIdx));
+ if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance && caps.instancing)
+ f->glVertexAttribDivisor(GLuint(locationIdx), GLuint(inputBinding->instanceStepRate()));
}
} else {
qWarning("No graphics pipeline active for setVertexInput; ignored");
@@ -1934,10 +2013,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.draw.ps);
if (psD) {
if (cmd.args.draw.instanceCount == 1 || !caps.instancing) {
- f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount);
+ f->glDrawArrays(psD->drawMode, GLint(cmd.args.draw.firstVertex), GLsizei(cmd.args.draw.vertexCount));
} else {
- f->glDrawArraysInstanced(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount,
- cmd.args.draw.instanceCount);
+ f->glDrawArraysInstanced(psD->drawMode, GLint(cmd.args.draw.firstVertex), GLsizei(cmd.args.draw.vertexCount),
+ GLsizei(cmd.args.draw.instanceCount));
}
} else {
qWarning("No graphics pipeline active for draw; ignored");
@@ -1953,30 +2032,30 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
f->glDrawElementsBaseVertex(psD->drawMode,
- cmd.args.drawIndexed.indexCount,
+ GLsizei(cmd.args.drawIndexed.indexCount),
indexType,
ofs,
cmd.args.drawIndexed.baseVertex);
} else {
f->glDrawElements(psD->drawMode,
- cmd.args.drawIndexed.indexCount,
+ GLsizei(cmd.args.drawIndexed.indexCount),
indexType,
ofs);
}
} else {
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
f->glDrawElementsInstancedBaseVertex(psD->drawMode,
- cmd.args.drawIndexed.indexCount,
+ GLsizei(cmd.args.drawIndexed.indexCount),
indexType,
ofs,
- cmd.args.drawIndexed.instanceCount,
+ GLsizei(cmd.args.drawIndexed.instanceCount),
cmd.args.drawIndexed.baseVertex);
} else {
f->glDrawElementsInstanced(psD->drawMode,
- cmd.args.drawIndexed.indexCount,
+ GLsizei(cmd.args.drawIndexed.indexCount),
indexType,
ofs,
- cmd.args.drawIndexed.instanceCount);
+ GLsizei(cmd.args.drawIndexed.instanceCount));
}
}
} else {
@@ -2001,7 +2080,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
const int colorAttCount = cmd.args.bindFramebuffer.colorAttCount;
QVarLengthArray<GLenum, 8> bufs;
for (int i = 0; i < colorAttCount; ++i)
- bufs.append(GL_COLOR_ATTACHMENT0 + i);
+ bufs.append(GL_COLOR_ATTACHMENT0 + uint(i));
f->glDrawBuffers(colorAttCount, bufs.constData());
}
} else {
@@ -2029,7 +2108,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
f->glClearDepthf(cmd.args.clear.d);
}
if (cmd.args.clear.mask & GL_STENCIL_BUFFER_BIT)
- f->glClearStencil(cmd.args.clear.s);
+ f->glClearStencil(GLint(cmd.args.clear.s));
f->glClear(cmd.args.clear.mask);
break;
case QGles2CommandBuffer::Command::BufferSubData:
@@ -2037,6 +2116,33 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
f->glBufferSubData(cmd.args.bufferSubData.target, cmd.args.bufferSubData.offset, cmd.args.bufferSubData.size,
cmd.args.bufferSubData.data);
break;
+ case QGles2CommandBuffer::Command::GetBufferSubData:
+ {
+ QRhiBufferReadbackResult *result = cmd.args.getBufferSubData.result;
+ f->glBindBuffer(cmd.args.getBufferSubData.target, cmd.args.getBufferSubData.buffer);
+ if (caps.gles) {
+ if (caps.properMapBuffer) {
+ void *p = f->glMapBufferRange(cmd.args.getBufferSubData.target,
+ cmd.args.getBufferSubData.offset,
+ cmd.args.getBufferSubData.size,
+ GL_MAP_READ_BIT);
+ if (p) {
+ result->data.resize(cmd.args.getBufferSubData.size);
+ memcpy(result->data.data(), p, size_t(cmd.args.getBufferSubData.size));
+ f->glUnmapBuffer(cmd.args.getBufferSubData.target);
+ }
+ }
+ } else {
+ result->data.resize(cmd.args.getBufferSubData.size);
+ f->glGetBufferSubData(cmd.args.getBufferSubData.target,
+ cmd.args.getBufferSubData.offset,
+ cmd.args.getBufferSubData.size,
+ result->data.data());
+ }
+ if (result->completed)
+ result->completed();
+ }
+ break;
case QGles2CommandBuffer::Command::CopyTex:
{
GLuint fbo;
@@ -2058,23 +2164,31 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
QRhiReadbackResult *result = cmd.args.readPixels.result;
GLuint tex = cmd.args.readPixels.texture;
GLuint fbo = 0;
+ int mipLevel = 0;
if (tex) {
result->pixelSize = QSize(cmd.args.readPixels.w, cmd.args.readPixels.h);
result->format = cmd.args.readPixels.format;
- f->glGenFramebuffers(1, &fbo);
- f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- cmd.args.readPixels.readTarget, cmd.args.readPixels.texture, cmd.args.readPixels.level);
+ mipLevel = cmd.args.readPixels.level;
+ if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
+ f->glGenFramebuffers(1, &fbo);
+ f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ cmd.args.readPixels.readTarget, cmd.args.readPixels.texture, mipLevel);
+ }
} else {
result->pixelSize = currentSwapChain->pixelSize;
result->format = QRhiTexture::RGBA8;
// readPixels handles multisample resolving implicitly
}
result->data.resize(result->pixelSize.width() * result->pixelSize.height() * 4);
- // With GLES (2.0?) GL_RGBA is the only mandated readback format, so stick with it.
- f->glReadPixels(0, 0, result->pixelSize.width(), result->pixelSize.height(),
- GL_RGBA, GL_UNSIGNED_BYTE,
- result->data.data());
+ if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
+ // With GLES (2.0?) GL_RGBA is the only mandated readback format, so stick with it.
+ f->glReadPixels(0, 0, result->pixelSize.width(), result->pixelSize.height(),
+ GL_RGBA, GL_UNSIGNED_BYTE,
+ result->data.data());
+ } else {
+ result->data.fill('\0');
+ }
if (fbo) {
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
f->glDeleteFramebuffers(1, &fbo);
@@ -2145,7 +2259,6 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
{
GLbitfield barriers = 0;
QRhiPassResourceTracker &tracker(cbD->passResTrackers[cmd.args.barriersForPass.trackerIndex]);
- const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
// we only care about after-write, not any other accesses, and
// cannot tell if something was written in a shader several passes
// ago: now the previously written resource may be used with an
@@ -2153,17 +2266,16 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
// barrier in theory. Hence setting all barrier bits whenever
// something previously written is used for the first time in a
// subsequent pass.
- for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
- QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(b.stateAtPassBegin.access);
+ for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
+ QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Buffer::AccessStorageWrite
|| accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
{
barriers |= GL_ALL_BARRIER_BITS;
}
}
- const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
- for (const QRhiPassResourceTracker::Texture &t : *textures) {
- QGles2Texture::Access accessBeforePass = QGles2Texture::Access(t.stateAtPassBegin.access);
+ for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
+ QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
if (accessBeforePass == QGles2Texture::AccessStorageWrite
|| accessBeforePass == QGles2Texture::AccessStorageReadWrite)
{
@@ -2222,6 +2334,7 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps)
}
} else {
f->glDisable(GL_BLEND);
+ f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
if (psD->m_depthTest)
f->glEnable(GL_DEPTH_TEST);
@@ -2264,7 +2377,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
int texUnit = 0;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -2273,7 +2386,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
if (dynOfsCount) {
for (int j = 0; j < dynOfsCount; ++j) {
if (dynOfsPairs[2 * j] == uint(b->binding)) {
- viewOffset = dynOfsPairs[2 * j + 1];
+ viewOffset = int(dynOfsPairs[2 * j + 1]);
break;
}
}
@@ -2364,20 +2477,20 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
for (QGles2SamplerDescription &sampler : samplers) {
if (sampler.binding == b->binding) {
- f->glActiveTexture(GL_TEXTURE0 + texUnit);
+ f->glActiveTexture(GL_TEXTURE0 + uint(texUnit));
f->glBindTexture(texD->target, texD->texture);
if (texD->samplerState != samplerD->d) {
- f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, samplerD->d.glminfilter);
- f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, samplerD->d.glmagfilter);
- f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, samplerD->d.glwraps);
- f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, samplerD->d.glwrapt);
+ f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter));
+ f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter));
+ f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps));
+ f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt));
// 3D textures not supported by GLES 2.0 or by us atm...
//f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, samplerD->d.glwrapr);
if (caps.textureCompareMode) {
if (samplerD->d.gltexcomparefunc != GL_NEVER) {
f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, samplerD->d.gltexcomparefunc);
+ f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc));
} else {
f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}
@@ -2404,7 +2517,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
access = GL_READ_ONLY;
else if (b->type == QRhiShaderResourceBinding::ImageStore)
access = GL_WRITE_ONLY;
- f->glBindImageTexture(b->binding, texD->texture,
+ f->glBindImageTexture(GLuint(b->binding), texD->texture,
b->u.simage.level, layered, 0,
access, texD->glsizedintformat);
}
@@ -2417,9 +2530,9 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
{
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf);
if (b->u.sbuf.offset == 0 && b->u.sbuf.maybeSize == 0)
- f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, b->binding, bufD->buffer);
+ f->glBindBufferBase(GL_SHADER_STORAGE_BUFFER, GLuint(b->binding), bufD->buffer);
else
- f->glBindBufferRange(GL_SHADER_STORAGE_BUFFER, b->binding, bufD->buffer,
+ f->glBindBufferRange(GL_SHADER_STORAGE_BUFFER, GLuint(b->binding), bufD->buffer,
b->u.sbuf.offset, b->u.sbuf.maybeSize ? b->u.sbuf.maybeSize : bufD->m_size);
}
break;
@@ -2470,10 +2583,12 @@ QGles2RenderTargetData *QRhiGles2::enqueueBindFramebuffer(QRhiRenderTarget *rt,
fbCmd.args.bindFramebuffer.fbo = rtTex->framebuffer;
fbCmd.args.bindFramebuffer.colorAttCount = rtD->colorAttCount;
- const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
- for (const QRhiColorAttachment &colorAttachment : colorAttachments) {
- QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAttachment.texture());
- QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAttachment.resolveTexture());
+ for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
+ it != itEnd; ++it)
+ {
+ const QRhiColorAttachment &colorAtt(*it);
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
+ QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
if (texD) {
trackedRegisterTexture(&passResTracker, texD,
QRhiPassResourceTracker::TexColorOutput,
@@ -2541,10 +2656,10 @@ void QRhiGles2::beginPass(QRhiCommandBuffer *cb,
clearCmd.args.clear.mask |= GL_COLOR_BUFFER_BIT;
if (rtD->dsAttCount && wantsDsClear)
clearCmd.args.clear.mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- clearCmd.args.clear.c[0] = colorClearValue.redF();
- clearCmd.args.clear.c[1] = colorClearValue.greenF();
- clearCmd.args.clear.c[2] = colorClearValue.blueF();
- clearCmd.args.clear.c[3] = colorClearValue.alphaF();
+ clearCmd.args.clear.c[0] = float(colorClearValue.redF());
+ clearCmd.args.clear.c[1] = float(colorClearValue.greenF());
+ clearCmd.args.clear.c[2] = float(colorClearValue.blueF());
+ clearCmd.args.clear.c[3] = float(colorClearValue.alphaF());
clearCmd.args.clear.d = depthStencilClearValue.depthClearValue();
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
cbD->commands.append(clearCmd);
@@ -2562,10 +2677,9 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, cbD->currentTarget);
- const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
- if (!colorAttachments.isEmpty()) {
+ if (rtTex->m_desc.cbeginColorAttachments() != rtTex->m_desc.cendColorAttachments()) {
// handle only 1 color attachment and only (msaa) renderbuffer
- const QRhiColorAttachment &colorAtt(colorAttachments[0]);
+ const QRhiColorAttachment &colorAtt(*rtTex->m_desc.cbeginColorAttachments());
if (colorAtt.resolveTexture()) {
Q_ASSERT(colorAtt.renderBuffer());
QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, colorAtt.renderBuffer());
@@ -2582,7 +2696,7 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
QGles2Texture *colorTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
const GLenum faceTargetBase = colorTexD->m_flags.testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X
: colorTexD->target;
- cmd.args.blitFromRb.target = faceTargetBase + colorAtt.resolveLayer();
+ cmd.args.blitFromRb.target = faceTargetBase + uint(colorAtt.resolveLayer());
cmd.args.blitFromRb.texture = colorTexD->texture;
cmd.args.blitFromRb.dstLevel = colorAtt.resolveLevel();
cbD->commands.append(cmd);
@@ -2649,9 +2763,9 @@ void QRhiGles2::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Dispatch;
- cmd.args.dispatch.x = x;
- cmd.args.dispatch.y = y;
- cmd.args.dispatch.z = z;
+ cmd.args.dispatch.x = GLuint(x);
+ cmd.args.dispatch.y = GLuint(y);
+ cmd.args.dispatch.z = GLuint(z);
cbD->commands.append(cmd);
}
@@ -2670,10 +2784,8 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
}
}
-bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
- QShaderDescription *desc, int *glslVersionUsed)
+QByteArray QRhiGles2::shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion)
{
- GLuint shader = f->glCreateShader(toGlShaderType(shaderStage.type()));
const QShader bakedShader = shaderStage.shader();
QVector<int> versionsToTry;
QByteArray source;
@@ -2691,8 +2803,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
QShaderVersion ver(v, QShaderVersion::GlslEs);
source = bakedShader.shader({ QShader::GlslShader, ver, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
- if (glslVersionUsed)
- *glslVersionUsed = v;
+ if (glslVersion)
+ *glslVersion = v;
break;
}
}
@@ -2721,8 +2833,8 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
for (int v : versionsToTry) {
source = bakedShader.shader({ QShader::GlslShader, v, shaderStage.shaderVariant() }).shader();
if (!source.isEmpty()) {
- if (glslVersionUsed)
- *glslVersionUsed = v;
+ if (glslVersion)
+ *glslVersion = v;
break;
}
}
@@ -2730,32 +2842,51 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
if (source.isEmpty()) {
qWarning() << "No GLSL shader code found (versions tried: " << versionsToTry
<< ") in baked shader" << bakedShader;
- return false;
}
+ return source;
+}
- const char *srcStr = source.constData();
- const GLint srcLength = source.count();
- f->glShaderSource(shader, 1, &srcStr, &srcLength);
- f->glCompileShader(shader);
- GLint compiled = 0;
- f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLint infoLogLength = 0;
- f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
- QByteArray log;
- if (infoLogLength > 1) {
- GLsizei length = 0;
- log.resize(infoLogLength);
- f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data());
- }
- qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData());
+bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion)
+{
+ const QByteArray source = shaderSource(shaderStage, glslVersion);
+ if (source.isEmpty())
return false;
+
+ GLuint shader;
+ auto cacheIt = m_shaderCache.constFind(shaderStage);
+ if (cacheIt != m_shaderCache.constEnd()) {
+ shader = *cacheIt;
+ } else {
+ shader = f->glCreateShader(toGlShaderType(shaderStage.type()));
+ const char *srcStr = source.constData();
+ const GLint srcLength = source.count();
+ f->glShaderSource(shader, 1, &srcStr, &srcLength);
+ f->glCompileShader(shader);
+ GLint compiled = 0;
+ f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLogLength = 0;
+ f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+ QByteArray log;
+ if (infoLogLength > 1) {
+ GLsizei length = 0;
+ log.resize(infoLogLength);
+ f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data());
+ }
+ qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData());
+ return false;
+ }
+ if (m_shaderCache.count() >= MAX_SHADER_CACHE_ENTRIES) {
+ // Use the simplest strategy: too many cached shaders -> drop them all.
+ for (uint shader : m_shaderCache)
+ f->glDeleteShader(shader); // does not actually get released yet when attached to a not-yet-released program
+ m_shaderCache.clear();
+ }
+ m_shaderCache.insert(shaderStage, shader);
}
f->glAttachShader(program, shader);
- f->glDeleteShader(shader);
- *desc = bakedShader.description();
return true;
}
@@ -2791,7 +2922,7 @@ void QRhiGles2::gatherUniforms(GLuint program, const QShaderDescription::Uniform
uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
if (uniform.glslLocation >= 0) {
uniform.binding = ub.binding;
- uniform.offset = blockMember.offset;
+ uniform.offset = uint(blockMember.offset);
uniform.size = blockMember.size;
dst->append(uniform);
}
@@ -2810,6 +2941,68 @@ void QRhiGles2::gatherSamplers(GLuint program, const QShaderDescription::InOutVa
}
}
+bool QRhiGles2::isProgramBinaryDiskCacheEnabled() const
+{
+ static QOpenGLProgramBinarySupportCheckWrapper checker;
+ return checker.get(ctx)->isSupported();
+}
+
+static QOpenGLProgramBinaryCache qrhi_programBinaryCache;
+
+static inline QShader::Stage toShaderStage(QRhiShaderStage::Type type)
+{
+ switch (type) {
+ case QRhiShaderStage::Vertex:
+ return QShader::VertexStage;
+ case QRhiShaderStage::Fragment:
+ return QShader::FragmentStage;
+ case QRhiShaderStage::Compute:
+ return QShader::ComputeStage;
+ default:
+ Q_UNREACHABLE();
+ return QShader::VertexStage;
+ }
+}
+
+QRhiGles2::DiskCacheResult QRhiGles2::tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
+ GLuint program, QByteArray *cacheKey)
+{
+ QRhiGles2::DiskCacheResult result = QRhiGles2::DiskCacheMiss;
+ QByteArray diskCacheKey;
+
+ if (isProgramBinaryDiskCacheEnabled()) {
+ QOpenGLProgramBinaryCache::ProgramDesc binaryProgram;
+ for (int i = 0; i < stageCount; ++i) {
+ const QRhiShaderStage &stage(stages[i]);
+ const QByteArray source = shaderSource(stage, nullptr);
+ if (source.isEmpty())
+ return QRhiGles2::DiskCacheError;
+ binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(toShaderStage(stage.type()), source));
+ }
+
+ diskCacheKey = binaryProgram.cacheKey();
+ if (qrhi_programBinaryCache.load(diskCacheKey, program)) {
+ qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache, program %u, key %s",
+ program, diskCacheKey.constData());
+ result = QRhiGles2::DiskCacheHit;
+ }
+ }
+
+ if (cacheKey)
+ *cacheKey = diskCacheKey;
+
+ return result;
+}
+
+void QRhiGles2::trySaveToDiskCache(GLuint program, const QByteArray &cacheKey)
+{
+ if (isProgramBinaryDiskCacheEnabled()) {
+ qCDebug(lcOpenGLProgramDiskCache, "Saving program binary, program %u, key %s",
+ program, cacheKey.constData());
+ qrhi_programBinaryCache.save(cacheKey, program);
+ }
+}
+
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
: QRhiBuffer(rhi, type, usage, size)
{
@@ -2855,7 +3048,7 @@ bool QGles2Buffer::build()
return false;
}
ubuf.resize(nonZeroSize);
- QRHI_PROF_F(newBuffer(this, nonZeroSize, 0, 1));
+ QRHI_PROF_F(newBuffer(this, uint(nonZeroSize), 0, 1));
return true;
}
@@ -2874,7 +3067,7 @@ bool QGles2Buffer::build()
usageState.access = AccessNone;
- QRHI_PROF_F(newBuffer(this, nonZeroSize, 1, 0));
+ QRHI_PROF_F(newBuffer(this, uint(nonZeroSize), 1, 0));
rhiD->registerResource(this);
return true;
}
@@ -3145,13 +3338,13 @@ bool QGles2Texture::build()
for (int layer = 0, layerCount = isCube ? 6 : 1; layer != layerCount; ++layer) {
for (int level = 0; level != mipLevelCount; ++level) {
const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
- rhiD->f->glTexImage2D(faceTargetBase + layer, level, glintformat,
+ rhiD->f->glTexImage2D(faceTargetBase + uint(layer), level, GLint(glintformat),
mipSize.width(), mipSize.height(), 0,
glformat, gltype, nullptr);
}
}
} else {
- rhiD->f->glTexImage2D(target, 0, glintformat, size.width(), size.height(),
+ rhiD->f->glTexImage2D(target, 0, GLint(glintformat), size.width(), size.height(),
0, glformat, gltype, nullptr);
}
} else {
@@ -3327,14 +3520,18 @@ bool QGles2TextureRenderTarget::build()
if (framebuffer)
release();
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
- Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture());
+ const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
+ Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
- if (colorAttachments.count() > rhiD->caps.maxDrawBuffers)
- qWarning("QGles2TextureRenderTarget: Too many color attachments (%d, max is %d)",
- colorAttachments.count(), rhiD->caps.maxDrawBuffers);
+ if (hasColorAttachments) {
+ const int count = m_desc.cendColorAttachments() - m_desc.cbeginColorAttachments();
+ if (count > rhiD->caps.maxDrawBuffers) {
+ qWarning("QGles2TextureRenderTarget: Too many color attachments (%d, max is %d)",
+ count, rhiD->caps.maxDrawBuffers);
+ }
+ }
if (m_desc.depthTexture() && !rhiD->caps.depthTexture)
qWarning("QGles2TextureRenderTarget: Depth texture is not supported and will be ignored");
@@ -3344,9 +3541,11 @@ bool QGles2TextureRenderTarget::build()
rhiD->f->glGenFramebuffers(1, &framebuffer);
rhiD->f->glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- d.colorAttCount = colorAttachments.count();
- for (int i = 0; i < d.colorAttCount; ++i) {
- const QRhiColorAttachment &colorAtt(colorAttachments[i]);
+ d.colorAttCount = 0;
+ int attIndex = 0;
+ for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
+ d.colorAttCount += 1;
+ const QRhiColorAttachment &colorAtt(*it);
QRhiTexture *texture = colorAtt.texture();
QRhiRenderBuffer *renderBuffer = colorAtt.renderBuffer();
Q_ASSERT(texture || renderBuffer);
@@ -3354,15 +3553,16 @@ bool QGles2TextureRenderTarget::build()
QGles2Texture *texD = QRHI_RES(QGles2Texture, texture);
Q_ASSERT(texD->texture && texD->specified);
const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
- rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, faceTargetBase + colorAtt.layer(), texD->texture, colorAtt.level());
- if (i == 0) {
+ rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
+ texD->texture, colorAtt.level());
+ if (attIndex == 0) {
d.pixelSize = texD->pixelSize();
d.sampleCount = 1;
}
} else if (renderBuffer) {
QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, renderBuffer);
- rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, rbD->renderbuffer);
- if (i == 0) {
+ rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), GL_RENDERBUFFER, rbD->renderbuffer);
+ if (attIndex == 0) {
d.pixelSize = rbD->pixelSize();
d.sampleCount = rbD->samples;
}
@@ -3491,32 +3691,50 @@ bool QGles2GraphicsPipeline::build()
if (!rhiD->ensureContext())
return false;
+ if (!rhiD->sanityCheckGraphicsPipeline(this))
+ return false;
+
drawMode = toGlTopology(m_topology);
program = rhiD->f->glCreateProgram();
+ QByteArray diskCacheKey;
+ QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(m_shaderStages.constData(),
+ m_shaderStages.count(),
+ program,
+ &diskCacheKey);
+ if (diskCacheResult == QRhiGles2::DiskCacheError)
+ return false;
+
+ const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
+
QShaderDescription vsDesc;
QShaderDescription fsDesc;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
if (isVertex) {
- if (!rhiD->compileShader(program, shaderStage, &vsDesc, nullptr))
+ if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
+ vsDesc = shaderStage.shader().description();
} else if (isFragment) {
- if (!rhiD->compileShader(program, shaderStage, &fsDesc, nullptr))
+ if (needsCompile && !rhiD->compileShader(program, shaderStage, nullptr))
return false;
+ fsDesc = shaderStage.shader().description();
}
}
for (auto inVar : vsDesc.inputVariables()) {
const QByteArray name = inVar.name.toUtf8();
- rhiD->f->glBindAttribLocation(program, inVar.location, name.constData());
+ rhiD->f->glBindAttribLocation(program, GLuint(inVar.location), name.constData());
}
- if (!rhiD->linkProgram(program))
+ if (needsCompile && !rhiD->linkProgram(program))
return false;
+ if (needsCompile)
+ rhiD->trySaveToDiskCache(program, diskCacheKey);
+
for (const QShaderDescription::UniformBlock &ub : vsDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
@@ -3577,11 +3795,24 @@ bool QGles2ComputePipeline::build()
program = rhiD->f->glCreateProgram();
QShaderDescription csDesc;
- if (!rhiD->compileShader(program, m_shaderStage, &csDesc, nullptr))
+ QByteArray diskCacheKey;
+ QRhiGles2::DiskCacheResult diskCacheResult = rhiD->tryLoadFromDiskCache(&m_shaderStage, 1, program, &diskCacheKey);
+ if (diskCacheResult == QRhiGles2::DiskCacheError)
return false;
- if (!rhiD->linkProgram(program))
+
+ const bool needsCompile = diskCacheResult == QRhiGles2::DiskCacheMiss;
+
+ if (needsCompile && !rhiD->compileShader(program, m_shaderStage, nullptr))
return false;
+ csDesc = m_shaderStage.shader().description();
+
+ if (needsCompile && !rhiD->linkProgram(program))
+ return false;
+
+ if (needsCompile)
+ rhiD->trySaveToDiskCache(program, diskCacheKey);
+
for (const QShaderDescription::UniformBlock &ub : csDesc.uniformBlocks())
rhiD->gatherUniforms(program, ub, &uniforms);
for (const QShaderDescription::InOutVariable &v : csDesc.combinedImageSamplers())
@@ -3655,9 +3886,16 @@ bool QGles2SwapChain::buildOrResize()
m_currentPixelSize = surfacePixelSize();
pixelSize = m_currentPixelSize;
+ if (m_depthStencil && m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)
+ && m_depthStencil->pixelSize() != pixelSize)
+ {
+ m_depthStencil->setPixelSize(pixelSize);
+ m_depthStencil->build();
+ }
+
rt.d.rp = QRHI_RES(QGles2RenderPassDescriptor, m_renderPassDesc);
rt.d.pixelSize = pixelSize;
- rt.d.dpr = m_window->devicePixelRatio();
+ rt.d.dpr = float(m_window->devicePixelRatio());
rt.d.sampleCount = qBound(1, m_sampleCount, 64);
rt.d.colorAttCount = 1;
rt.d.dsAttCount = m_depthStencil ? 1 : 0;
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index 6da529be92..8814d9c19d 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -312,8 +312,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
BindShaderResources,
BindFramebuffer,
Clear,
- BufferData,
BufferSubData,
+ GetBufferSubData,
CopyTex,
ReadPixels,
SubImage,
@@ -402,6 +402,13 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
const void *data; // must come from retainData()
} bufferSubData;
struct {
+ QRhiBufferReadbackResult *result;
+ GLenum target;
+ GLuint buffer;
+ int offset;
+ int size;
+ } getBufferSubData;
+ struct {
GLenum srcFaceTarget;
GLuint srcTexture;
int srcLevel;
@@ -664,7 +671,9 @@ public:
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
- void makeThreadLocalNativeContextCurrent() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
bool ensureContext(QSurface *surface = nullptr) const;
void executeDeferredReleases();
@@ -690,13 +699,23 @@ public:
bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
int effectiveSampleCount(int sampleCount) const;
- bool compileShader(GLuint program, const QRhiShaderStage &shaderStage,
- QShaderDescription *desc, int *glslVersionUsed);
+ QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
+ bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program);
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst);
+ bool isProgramBinaryDiskCacheEnabled() const;
+
+ enum DiskCacheResult {
+ DiskCacheHit,
+ DiskCacheMiss,
+ DiskCacheError
+ };
+ DiskCacheResult tryLoadFromDiskCache(const QRhiShaderStage *stages, int stageCount,
+ GLuint program, QByteArray *cacheKey);
+ void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
QOpenGLContext *ctx = nullptr;
bool importedContext = false;
@@ -732,7 +751,10 @@ public:
rgba8Format(false),
instancing(false),
baseVertex(false),
- compute(false)
+ compute(false),
+ textureCompareMode(false),
+ properMapBuffer(false),
+ nonBaseLevelFramebufferTexture(false)
{ }
int ctxMajor;
int ctxMinor;
@@ -763,11 +785,14 @@ public:
uint baseVertex : 1;
uint compute : 1;
uint textureCompareMode : 1;
+ uint properMapBuffer : 1;
+ uint nonBaseLevelFramebufferTexture : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QVector<GLint> supportedCompressedFormats;
mutable QVector<int> supportedSampleCountList;
QRhiGles2NativeHandles nativeHandlesStruct;
+ mutable bool contextLost = false;
struct DeferredReleaseEntry {
enum Type {
@@ -804,6 +829,8 @@ public:
bool active = false;
QGles2CommandBuffer cbWrapper;
} ofr;
+
+ QHash<QRhiShaderStage, uint> m_shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_MOVABLE_TYPE);
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 07753c985c..5f14d917b8 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -138,6 +138,20 @@ QT_BEGIN_NAMESPACE
\l{QRhiCommandBuffer::endPass()}.
*/
+struct QMetalShader
+{
+ id<MTLLibrary> lib = nil;
+ id<MTLFunction> func = nil;
+ std::array<uint, 3> localSize;
+
+ void release() {
+ [lib release];
+ lib = nil;
+ [func release];
+ func = nil;
+ }
+};
+
struct QRhiMetalData
{
QRhiMetalData(QRhiImplementation *rhi) : ofr(rhi) { }
@@ -191,7 +205,7 @@ struct QRhiMetalData
QMetalCommandBuffer cbWrapper;
} ofr;
- struct ActiveReadback {
+ struct TextureReadback {
int activeFrameSlot = -1;
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
@@ -200,23 +214,25 @@ struct QRhiMetalData
QSize pixelSize;
QRhiTexture::Format format;
};
- QVector<ActiveReadback> activeReadbacks;
+ QVector<TextureReadback> activeTextureReadbacks;
API_AVAILABLE(macos(10.13), ios(11.0)) MTLCaptureManager *captureMgr;
API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil;
static const int TEXBUF_ALIGN = 256; // probably not accurate
+
+ QHash<QRhiShaderStage, QMetalShader> shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiMetalData::ActiveReadback, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiMetalData::TextureReadback, Q_MOVABLE_TYPE);
struct QMetalBufferData
{
bool managed;
bool slotted;
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
- QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
+ QVarLengthArray<QRhiResourceUpdateBatchPrivate::BufferOp, 16> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
};
struct QMetalRenderBufferData
@@ -289,17 +305,14 @@ struct QMetalGraphicsPipelineData
MTLPrimitiveType primitiveType;
MTLWinding winding;
MTLCullMode cullMode;
- id<MTLLibrary> vsLib = nil;
- id<MTLFunction> vsFunc = nil;
- id<MTLLibrary> fsLib = nil;
- id<MTLFunction> fsFunc = nil;
+ QMetalShader vs;
+ QMetalShader fs;
};
struct QMetalComputePipelineData
{
id<MTLComputePipelineState> ps = nil;
- id<MTLLibrary> csLib = nil;
- id<MTLFunction> csFunc = nil;
+ QMetalShader cs;
MTLSize localSize;
};
@@ -339,7 +352,8 @@ QRhiMetal::~QRhiMetal()
delete d;
}
-static inline uint aligned(uint v, uint byteAlign)
+template <class Int>
+inline Int aligned(Int v, Int byteAlign)
{
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
@@ -353,6 +367,11 @@ bool QRhiMetal::create(QRhi::Flags flags)
else
d->dev = MTLCreateSystemDefaultDevice();
+ if (!d->dev) {
+ qWarning("No MTLDevice");
+ return false;
+ }
+
qCDebug(QRHI_LOG_INFO, "Metal device: %s", qPrintable(QString::fromNSString([d->dev name])));
if (importedCmdQueue)
@@ -404,6 +423,10 @@ void QRhiMetal::destroy()
executeDeferredReleases(true);
finishActiveReadbacks(true);
+ for (QMetalShader &s : d->shaderCache)
+ s.release();
+ d->shaderCache.clear();
+
if (@available(macOS 10.13, iOS 11.0, *)) {
[d->captureScope release];
d->captureScope = nil;
@@ -532,6 +555,12 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::BaseInstance:
return true;
+ case QRhi::TriangleFanTopology:
+ return false;
+ case QRhi::ReadBackNonUniformBuffer:
+ return true;
+ case QRhi::ReadBackNonBaseMipLevel:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -565,9 +594,23 @@ void QRhiMetal::sendVMemStatsToProfiler()
// nothing to do here
}
-void QRhiMetal::makeThreadLocalNativeContextCurrent()
+bool QRhiMetal::makeThreadLocalNativeContextCurrent()
{
- // nothing to do here
+ // not applicable
+ return false;
+}
+
+void QRhiMetal::releaseCachedResources()
+{
+ for (QMetalShader &s : d->shaderCache)
+ s.release();
+
+ d->shaderCache.clear();
+}
+
+bool QRhiMetal::isDeviceLost() const
+{
+ return false;
}
QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
@@ -624,13 +667,13 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
} res[KNOWN_STAGES];
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
+ const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
- uint offset = b->u.ubuf.offset;
+ uint offset = uint(b->u.ubuf.offset);
for (int i = 0; i < dynamicOffsetCount; ++i) {
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
if (dynOfs.first == b->binding) {
@@ -694,7 +737,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
- uint offset = b->u.sbuf.offset;
+ uint offset = uint(b->u.sbuf.offset);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].buffers.feed(b->binding, mtlbuf);
res[0].bufferOffsets.feed(b->binding, offset);
@@ -726,17 +769,17 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
case 0:
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -755,15 +798,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
switch (idx) {
case 0:
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -775,15 +818,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
switch (idx) {
case 0:
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
- withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
+ withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
default:
Q_UNREACHABLE();
@@ -806,8 +849,15 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
[cbD->d->currentRenderPassEncoder setRenderPipelineState: psD->d->ps];
[cbD->d->currentRenderPassEncoder setDepthStencilState: psD->d->ds];
- [cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode];
- [cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding];
+
+ if (cbD->currentCullMode == -1 || psD->d->cullMode != uint(cbD->currentCullMode)) {
+ [cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode];
+ cbD->currentCullMode = int(psD->d->cullMode);
+ }
+ if (cbD->currentFrontFaceWinding == -1 || psD->d->winding != uint(cbD->currentFrontFaceWinding)) {
+ [cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding];
+ cbD->currentFrontFaceWinding = int(psD->d->winding);
+ }
}
psD->lastActiveFrameSlot = currentFrameSlot;
@@ -836,7 +886,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
// do buffer writes, figure out if we need to rebind, and mark as in-use
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -981,7 +1031,7 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
[cbD->d->currentRenderPassEncoder setVertexBuffers:
bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
- withRange: NSMakeRange(firstVertexBinding + bufferBatch.startBinding, bufferBatch.resources.count())];
+ withRange: NSMakeRange(uint(firstVertexBinding) + bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
}
}
@@ -1009,21 +1059,21 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
return;
MTLViewport vp;
- vp.originX = x;
- vp.originY = y;
- vp.width = w;
- vp.height = h;
- vp.znear = viewport.minDepth();
- vp.zfar = viewport.maxDepth();
+ vp.originX = double(x);
+ vp.originY = double(y);
+ vp.width = double(w);
+ vp.height = double(h);
+ vp.znear = double(viewport.minDepth());
+ vp.zfar = double(viewport.maxDepth());
[cbD->d->currentRenderPassEncoder setViewport: vp];
if (!QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
MTLScissorRect s;
- s.x = x;
- s.y = y;
- s.width = w;
- s.height = h;
+ s.x = NSUInteger(x);
+ s.y = NSUInteger(y);
+ s.width = NSUInteger(w);
+ s.height = NSUInteger(h);
[cbD->d->currentRenderPassEncoder setScissorRect: s];
}
}
@@ -1041,10 +1091,10 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
return;
MTLScissorRect s;
- s.x = x;
- s.y = y;
- s.width = w;
- s.height = h;
+ s.x = NSUInteger(x);
+ s.y = NSUInteger(y);
+ s.width = NSUInteger(w);
+ s.height = NSUInteger(h);
[cbD->d->currentRenderPassEncoder setScissorRect: s];
}
@@ -1054,7 +1104,8 @@ void QRhiMetal::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
- [cbD->d->currentRenderPassEncoder setBlendColorRed: c.redF() green: c.greenF() blue: c.blueF() alpha: c.alphaF()];
+ [cbD->d->currentRenderPassEncoder setBlendColorRed: float(c.redF())
+ green: float(c.greenF()) blue: float(c.blueF()) alpha: float(c.alphaF())];
}
void QRhiMetal::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
@@ -1086,7 +1137,7 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
return;
const quint32 indexOffset = cbD->currentIndexOffset + firstIndex * (cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? 2 : 4);
- Q_ASSERT(indexOffset == aligned(indexOffset, 4));
+ Q_ASSERT(indexOffset == aligned<quint32>(indexOffset, 4));
QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer);
id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0];
@@ -1344,7 +1395,7 @@ MTLRenderPassDescriptor *QRhiMetalData::createDefaultRenderPass(bool hasDepthSte
MTLClearColor c = MTLClearColorMake(colorClearValue.redF(), colorClearValue.greenF(), colorClearValue.blueF(),
colorClearValue.alphaF());
- for (int i = 0; i < colorAttCount; ++i) {
+ for (uint i = 0; i < uint(colorAttCount); ++i) {
rp.colorAttachments[i].loadAction = MTLLoadActionClear;
rp.colorAttachments[i].storeAction = MTLStoreActionStore;
rp.colorAttachments[i].clearColor = c;
@@ -1355,7 +1406,7 @@ MTLRenderPassDescriptor *QRhiMetalData::createDefaultRenderPass(bool hasDepthSte
rp.depthAttachment.storeAction = MTLStoreActionDontCare;
rp.stencilAttachment.loadAction = MTLLoadActionClear;
rp.stencilAttachment.storeAction = MTLStoreActionDontCare;
- rp.depthAttachment.clearDepth = depthStencilClearValue.depthClearValue();
+ rp.depthAttachment.clearDepth = double(depthStencilClearValue.depthClearValue());
rp.stencilAttachment.clearStencil = depthStencilClearValue.stencilClearValue();
}
@@ -1368,7 +1419,7 @@ qsizetype QRhiMetal::subresUploadByteSize(const QRhiTextureSubresourceUploadDesc
const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
subresDesc.data().size() : subresDesc.image().sizeInBytes();
if (imageSizeBytes > 0)
- size += aligned(imageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
+ size += aligned<qsizetype>(imageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
return size;
}
@@ -1396,31 +1447,31 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
h = subresDesc.sourceSize().height();
}
if (img.depth() == 32) {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
srcOffset = sy * bpl + sx * 4;
// bpl remains set to the original image's row stride
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
Q_ASSERT(img.sizeInBytes() <= fullImageSizeBytes);
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), img.sizeInBytes());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(img.sizeInBytes()));
}
} else {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
}
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs + srcOffset
- sourceBytesPerRow: bpl
+ sourceOffset: NSUInteger(*curOfs + srcOffset)
+ sourceBytesPerRow: NSUInteger(bpl)
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)
options: MTLBlitOptionNone];
- *curOfs += aligned(fullImageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
+ *curOfs += aligned<qsizetype>(fullImageSizeBytes, QRhiMetalData::TEXBUF_ALIGN);
} else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
const QSize subresSize = q->sizeForMipLevel(level, texD->m_pixelSize);
const int subresw = subresSize.width();
@@ -1445,17 +1496,17 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
if (dy + h != subresh)
h = aligned(h, blockDim.height());
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), rawData.size());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: bpl
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dx, dy, 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dx), NSUInteger(dy), 0)
options: MTLBlitOptionNone];
*curOfs += aligned(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
@@ -1474,17 +1525,17 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
quint32 bpl = 0;
textureFormatInfo(texD->m_format, QSize(w, h), &bpl, nullptr);
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), rawData.size());
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, rawData.constData(), size_t(rawData.size()));
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: *curOfs
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: bpl
sourceBytesPerImage: 0
- sourceSize: MTLSizeMake(w, h, 1)
+ sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
toTexture: texD->d->tex
- destinationSlice: layer
- destinationLevel: level
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)
+ destinationSlice: NSUInteger(layer)
+ destinationLevel: NSUInteger(level)
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)
options: MTLBlitOptionNone];
*curOfs += aligned(rawData.size(), QRhiMetalData::TEXBUF_ALIGN);
@@ -1499,21 +1550,33 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
- QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
- Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
- bufD->d->pendingUpdates[i].append(u);
- }
-
- // Due to the Metal API the handling of static and dynamic buffers is
- // basically the same. So go through the same pendingUpdates machinery.
- for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
- QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
- Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
- for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
- bufD->d->pendingUpdates[i].append({ u.buf, u.offset, u.data.size(), u.data.constData() });
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
+ if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
+ QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
+ Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
+ for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
+ bufD->d->pendingUpdates[i].append(u);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
+ // Due to the Metal API the handling of static and dynamic buffers is
+ // basically the same. So go through the same pendingUpdates machinery.
+ QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
+ Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
+ for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
+ bufD->d->pendingUpdates[i].append(
+ QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(u.buf, u.offset, u.data.size(), u.data.constData()));
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
+ QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
+ executeBufferHostWritesForCurrentFrame(bufD);
+ const int idx = bufD->d->slotted ? currentFrameSlot : 0;
+ char *p = reinterpret_cast<char *>([bufD->d->buf[idx] contents]);
+ if (p) {
+ u.result->data.resize(u.readSize);
+ memcpy(u.result->data.data(), p + u.offset, size_t(u.readSize));
+ }
+ if (u.result->completed)
+ u.result->completed();
+ }
}
id<MTLBlitCommandEncoder> blitEnc = nil;
@@ -1527,26 +1590,26 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
- QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.upload.tex);
+ QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.dst);
qsizetype stagingSize = 0;
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
stagingSize += subresUploadByteSize(subresDesc);
}
}
ensureBlit();
Q_ASSERT(!utexD->d->stagingBuf[currentFrameSlot]);
- utexD->d->stagingBuf[currentFrameSlot] = [d->dev newBufferWithLength: stagingSize
+ utexD->d->stagingBuf[currentFrameSlot] = [d->dev newBufferWithLength: NSUInteger(stagingSize)
options: MTLResourceStorageModeShared];
- QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, stagingSize));
+ QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, quint32(stagingSize)));
void *mp = [utexD->d->stagingBuf[currentFrameSlot] contents];
qsizetype curOfs = 0;
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
enqueueSubresUpload(utexD, mp, blitEnc, layer, level, subresDesc, &curOfs);
}
}
@@ -1561,32 +1624,33 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
d->releaseQueue.append(e);
QRHI_PROF_F(releaseTextureStagingArea(utexD, currentFrameSlot));
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
- Q_ASSERT(u.copy.src && u.copy.dst);
- QMetalTexture *srcD = QRHI_RES(QMetalTexture, u.copy.src);
- QMetalTexture *dstD = QRHI_RES(QMetalTexture, u.copy.dst);
- const QPoint dp = u.copy.desc.destinationTopLeft();
- const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
- const QPoint sp = u.copy.desc.sourceTopLeft();
+ Q_ASSERT(u.src && u.dst);
+ QMetalTexture *srcD = QRHI_RES(QMetalTexture, u.src);
+ QMetalTexture *dstD = QRHI_RES(QMetalTexture, u.dst);
+ const QPoint dp = u.desc.destinationTopLeft();
+ const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
+ const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
+ const QPoint sp = u.desc.sourceTopLeft();
ensureBlit();
[blitEnc copyFromTexture: srcD->d->tex
- sourceSlice: u.copy.desc.sourceLayer()
- sourceLevel: u.copy.desc.sourceLevel()
- sourceOrigin: MTLOriginMake(sp.x(), sp.y(), 0)
- sourceSize: MTLSizeMake(size.width(), size.height(), 1)
+ sourceSlice: NSUInteger(u.desc.sourceLayer())
+ sourceLevel: NSUInteger(u.desc.sourceLevel())
+ sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), 0)
+ sourceSize: MTLSizeMake(NSUInteger(copySize.width()), NSUInteger(copySize.height()), 1)
toTexture: dstD->d->tex
- destinationSlice: u.copy.desc.destinationLayer()
- destinationLevel: u.copy.desc.destinationLevel()
- destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)];
+ destinationSlice: NSUInteger(u.desc.destinationLayer())
+ destinationLevel: NSUInteger(u.desc.destinationLevel())
+ destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)];
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
- QRhiMetalData::ActiveReadback aRb;
- aRb.activeFrameSlot = currentFrameSlot;
- aRb.desc = u.read.rb;
- aRb.result = u.read.result;
+ QRhiMetalData::TextureReadback readback;
+ readback.activeFrameSlot = currentFrameSlot;
+ readback.desc = u.rb;
+ readback.result = u.result;
- QMetalTexture *texD = QRHI_RES(QMetalTexture, u.read.rb.texture());
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, u.rb.texture());
QMetalSwapChain *swapChainD = nullptr;
id<MTLTexture> src;
QSize srcSize;
@@ -1595,17 +1659,16 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
qWarning("Multisample texture cannot be read back");
continue;
}
- aRb.pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize)
- : texD->m_pixelSize;
- aRb.format = texD->m_format;
+ readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
+ readback.format = texD->m_format;
src = texD->d->tex;
- srcSize = texD->m_pixelSize;
+ srcSize = readback.pixelSize;
texD->lastActiveFrameSlot = currentFrameSlot;
} else {
Q_ASSERT(currentSwapChain);
swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
- aRb.pixelSize = swapChainD->pixelSize;
- aRb.format = swapChainD->d->rhiColorFormat;
+ readback.pixelSize = swapChainD->pixelSize;
+ readback.format = swapChainD->d->rhiColorFormat;
// Multisample swapchains need nothing special since resolving
// happens when ending a renderpass.
const QMetalRenderTargetData::ColorAtt &colorAtt(swapChainD->rtWrapper.d->fb.colorAtt[0]);
@@ -1614,28 +1677,28 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
quint32 bpl = 0;
- textureFormatInfo(aRb.format, aRb.pixelSize, &bpl, &aRb.bufSize);
- aRb.buf = [d->dev newBufferWithLength: aRb.bufSize options: MTLResourceStorageModeShared];
+ textureFormatInfo(readback.format, readback.pixelSize, &bpl, &readback.bufSize);
+ readback.buf = [d->dev newBufferWithLength: readback.bufSize options: MTLResourceStorageModeShared];
- QRHI_PROF_F(newReadbackBuffer(quint64(quintptr(aRb.buf)),
+ QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(readback.buf)),
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
- aRb.bufSize));
+ readback.bufSize));
ensureBlit();
[blitEnc copyFromTexture: src
- sourceSlice: u.read.rb.layer()
- sourceLevel: u.read.rb.level()
+ sourceSlice: NSUInteger(u.rb.layer())
+ sourceLevel: NSUInteger(u.rb.level())
sourceOrigin: MTLOriginMake(0, 0, 0)
- sourceSize: MTLSizeMake(srcSize.width(), srcSize.height(), 1)
- toBuffer: aRb.buf
+ sourceSize: MTLSizeMake(NSUInteger(srcSize.width()), NSUInteger(srcSize.height()), 1)
+ toBuffer: readback.buf
destinationOffset: 0
destinationBytesPerRow: bpl
destinationBytesPerImage: 0
options: MTLBlitOptionNone];
- d->activeReadbacks.append(aRb);
- } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
- QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.mipgen.tex);
+ d->activeTextureReadbacks.append(readback);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
+ QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.dst);
ensureBlit();
[blitEnc generateMipmapsForTexture: utexD->d->tex];
utexD->lastActiveFrameSlot = currentFrameSlot;
@@ -1655,25 +1718,24 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
{
const int idx = bufD->d->slotted ? currentFrameSlot : 0;
- QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->d->pendingUpdates[idx]);
- if (updates.isEmpty())
+ if (bufD->d->pendingUpdates[idx].isEmpty())
return;
void *p = [bufD->d->buf[idx] contents];
int changeBegin = -1;
int changeEnd = -1;
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : updates) {
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) {
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
- memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), u.data.size());
+ memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
changeEnd = u.offset + u.data.size();
}
if (changeBegin >= 0 && bufD->d->managed)
- [bufD->d->buf[idx] didModifyRange: NSMakeRange(changeBegin, changeEnd - changeBegin)];
+ [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
- updates.clear();
+ bufD->d->pendingUpdates[idx].clear();
}
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -1728,21 +1790,22 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
rtD = rtTex->d;
cbD->d->currentPassRpDesc = d->createDefaultRenderPass(rtD->dsAttCount, colorClearValue, depthStencilClearValue, rtD->colorAttCount);
if (rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents)) {
- for (int i = 0; i < rtD->colorAttCount; ++i)
+ for (uint i = 0; i < uint(rtD->colorAttCount); ++i)
cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
if (rtD->dsAttCount && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents)) {
cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
- const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
- for (const QRhiColorAttachment &colorAttachment : colorAttachments) {
- if (colorAttachment.texture())
- QRHI_RES(QMetalTexture, colorAttachment.texture())->lastActiveFrameSlot = currentFrameSlot;
- else if (colorAttachment.renderBuffer())
- QRHI_RES(QMetalRenderBuffer, colorAttachment.renderBuffer())->lastActiveFrameSlot = currentFrameSlot;
- if (colorAttachment.resolveTexture())
- QRHI_RES(QMetalTexture, colorAttachment.resolveTexture())->lastActiveFrameSlot = currentFrameSlot;
+ for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
+ it != itEnd; ++it)
+ {
+ if (it->texture())
+ QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot;
+ else if (it->renderBuffer())
+ QRHI_RES(QMetalRenderBuffer, it->renderBuffer())->lastActiveFrameSlot = currentFrameSlot;
+ if (it->resolveTexture())
+ QRHI_RES(QMetalTexture, it->resolveTexture())->lastActiveFrameSlot = currentFrameSlot;
}
if (rtTex->m_desc.depthStencilBuffer())
QRHI_RES(QMetalRenderBuffer, rtTex->m_desc.depthStencilBuffer())->lastActiveFrameSlot = currentFrameSlot;
@@ -1755,15 +1818,15 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
break;
}
- for (int i = 0; i < rtD->colorAttCount; ++i) {
+ for (uint i = 0; i < uint(rtD->colorAttCount); ++i) {
cbD->d->currentPassRpDesc.colorAttachments[i].texture = rtD->fb.colorAtt[i].tex;
- cbD->d->currentPassRpDesc.colorAttachments[i].slice = rtD->fb.colorAtt[i].layer;
- cbD->d->currentPassRpDesc.colorAttachments[i].level = rtD->fb.colorAtt[i].level;
+ cbD->d->currentPassRpDesc.colorAttachments[i].slice = NSUInteger(rtD->fb.colorAtt[i].layer);
+ cbD->d->currentPassRpDesc.colorAttachments[i].level = NSUInteger(rtD->fb.colorAtt[i].level);
if (rtD->fb.colorAtt[i].resolveTex) {
cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = MTLStoreActionMultisampleResolve;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveTexture = rtD->fb.colorAtt[i].resolveTex;
- cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = rtD->fb.colorAtt[i].resolveLayer;
- cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = rtD->fb.colorAtt[i].resolveLevel;
+ cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = NSUInteger(rtD->fb.colorAtt[i].resolveLayer);
+ cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = NSUInteger(rtD->fb.colorAtt[i].resolveLevel);
}
}
@@ -1845,7 +1908,7 @@ void QRhiMetal::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::ComputePass);
QMetalComputePipeline *psD = QRHI_RES(QMetalComputePipeline, cbD->currentComputePipeline);
- [cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(x, y, z)
+ [cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(NSUInteger(x), NSUInteger(y), NSUInteger(z))
threadsPerThreadgroup: psD->d->localSize];
}
@@ -1908,22 +1971,22 @@ void QRhiMetal::finishActiveReadbacks(bool forced)
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (int i = d->activeReadbacks.count() - 1; i >= 0; --i) {
- const QRhiMetalData::ActiveReadback &aRb(d->activeReadbacks[i]);
- if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
- aRb.result->format = aRb.format;
- aRb.result->pixelSize = aRb.pixelSize;
- aRb.result->data.resize(aRb.bufSize);
- void *p = [aRb.buf contents];
- memcpy(aRb.result->data.data(), p, aRb.bufSize);
- [aRb.buf release];
+ for (int i = d->activeTextureReadbacks.count() - 1; i >= 0; --i) {
+ const QRhiMetalData::TextureReadback &readback(d->activeTextureReadbacks[i]);
+ if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
+ readback.result->format = readback.format;
+ readback.result->pixelSize = readback.pixelSize;
+ readback.result->data.resize(int(readback.bufSize));
+ void *p = [readback.buf contents];
+ memcpy(readback.result->data.data(), p, readback.bufSize);
+ [readback.buf release];
- QRHI_PROF_F(releaseReadbackBuffer(quint64(quintptr(aRb.buf))));
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.buf))));
- if (aRb.result->completed)
- completedCallbacks.append(aRb.result->completed);
+ if (readback.result->completed)
+ completedCallbacks.append(readback.result->completed);
- d->activeReadbacks.removeAt(i);
+ d->activeTextureReadbacks.removeAt(i);
}
}
@@ -1977,8 +2040,8 @@ bool QMetalBuffer::build()
return false;
}
- const int nonZeroSize = m_size <= 0 ? 256 : m_size;
- const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
+ const uint nonZeroSize = m_size <= 0 ? 256 : uint(m_size);
+ const uint roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned<uint>(nonZeroSize, 256) : nonZeroSize;
d->managed = false;
MTLResourceOptions opts = MTLResourceStorageModeShared;
@@ -1999,7 +2062,6 @@ bool QMetalBuffer::build()
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
if (i == 0 || d->slotted) {
d->buf[i] = [rhiD->d->dev newBufferWithLength: roundedSize options: opts];
- d->pendingUpdates[i].reserve(16);
if (!m_objectName.isEmpty()) {
if (!d->slotted) {
d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
@@ -2065,10 +2127,10 @@ bool QMetalRenderBuffer::build()
MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
- desc.width = m_pixelSize.width();
- desc.height = m_pixelSize.height();
+ desc.width = NSUInteger(m_pixelSize.width());
+ desc.height = NSUInteger(m_pixelSize.height());
if (samples > 1)
- desc.sampleCount = samples;
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget;
@@ -2335,11 +2397,11 @@ bool QMetalTexture::build()
else
desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D;
desc.pixelFormat = d->format;
- desc.width = size.width();
- desc.height = size.height();
- desc.mipmapLevelCount = mipLevelCount;
+ desc.width = NSUInteger(size.width());
+ desc.height = NSUInteger(size.height());
+ desc.mipmapLevelCount = NSUInteger(mipLevelCount);
if (samples > 1)
- desc.sampleCount = samples;
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageShaderRead;
@@ -2405,7 +2467,7 @@ id<MTLTexture> QMetalTextureData::viewForLevel(int level)
const MTLTextureType type = [tex textureType];
const bool isCube = q->m_flags.testFlag(QRhiTexture::CubeMap);
id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type
- levels: NSMakeRange(level, 1) slices: NSMakeRange(0, isCube ? 6 : 1)];
+ levels: NSMakeRange(NSUInteger(level), 1) slices: NSMakeRange(0, isCube ? 6 : 1)];
perLevelViews[level] = view;
return view;
@@ -2607,60 +2669,63 @@ void QMetalTextureRenderTarget::release()
QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDescriptor()
{
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
+ const int colorAttachmentCount = m_desc.cendColorAttachments() - m_desc.cbeginColorAttachments();
QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi);
- rpD->colorAttachmentCount = colorAttachments.count();
+ rpD->colorAttachmentCount = colorAttachmentCount;
rpD->hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
- for (int i = 0, ie = colorAttachments.count(); i != ie; ++i) {
- QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAttachments[i].texture());
- QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAttachments[i].renderBuffer());
- rpD->colorFormat[i] = texD ? texD->d->format : rbD->d->format;
+ for (int i = 0; i < colorAttachmentCount; ++i) {
+ const QRhiColorAttachment *colorAtt = m_desc.colorAttachmentAt(i);
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAtt->texture());
+ QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAtt->renderBuffer());
+ rpD->colorFormat[i] = int(texD ? texD->d->format : rbD->d->format);
}
if (m_desc.depthTexture())
- rpD->dsFormat = QRHI_RES(QMetalTexture, m_desc.depthTexture())->d->format;
+ rpD->dsFormat = int(QRHI_RES(QMetalTexture, m_desc.depthTexture())->d->format);
else if (m_desc.depthStencilBuffer())
- rpD->dsFormat = QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format;
+ rpD->dsFormat = int(QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format);
return rpD;
}
bool QMetalTextureRenderTarget::build()
{
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
- Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture());
+ const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
+ Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
- d->colorAttCount = colorAttachments.count();
- for (int i = 0; i < d->colorAttCount; ++i) {
- QMetalTexture *texD = QRHI_RES(QMetalTexture, colorAttachments[i].texture());
- QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, colorAttachments[i].renderBuffer());
+ d->colorAttCount = 0;
+ int attIndex = 0;
+ for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
+ d->colorAttCount += 1;
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, it->texture());
+ QMetalRenderBuffer *rbD = QRHI_RES(QMetalRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
id<MTLTexture> dst = nil;
if (texD) {
dst = texD->d->tex;
- if (i == 0) {
+ if (attIndex == 0) {
d->pixelSize = texD->pixelSize();
d->sampleCount = texD->samples;
}
} else if (rbD) {
dst = rbD->d->tex;
- if (i == 0) {
+ if (attIndex == 0) {
d->pixelSize = rbD->pixelSize();
d->sampleCount = rbD->samples;
}
}
QMetalRenderTargetData::ColorAtt colorAtt;
colorAtt.tex = dst;
- colorAtt.layer = colorAttachments[i].layer();
- colorAtt.level = colorAttachments[i].level();
- QMetalTexture *resTexD = QRHI_RES(QMetalTexture, colorAttachments[i].resolveTexture());
+ colorAtt.layer = it->layer();
+ colorAtt.level = it->level();
+ QMetalTexture *resTexD = QRHI_RES(QMetalTexture, it->resolveTexture());
colorAtt.resolveTex = resTexD ? resTexD->d->tex : nil;
- colorAtt.resolveLayer = colorAttachments[i].resolveLayer();
- colorAtt.resolveLevel = colorAttachments[i].resolveLevel();
- d->fb.colorAtt[i] = colorAtt;
+ colorAtt.resolveLayer = it->resolveLayer();
+ colorAtt.resolveLevel = it->resolveLevel();
+ d->fb.colorAtt[attIndex] = colorAtt;
}
d->dpr = 1;
@@ -2728,21 +2793,21 @@ bool QMetalShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
- sortedBindings = m_bindings;
+ std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
- return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
+ return a.data()->binding < b.data()->binding;
});
if (!sortedBindings.isEmpty())
- maxBinding = QRhiShaderResourceBindingPrivate::get(&sortedBindings.last())->binding;
+ maxBinding = sortedBindings.last().data()->binding;
else
maxBinding = -1;
boundResourceData.resize(sortedBindings.count());
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -2810,36 +2875,17 @@ void QMetalGraphicsPipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
- if (!d->ps)
- return;
-
- if (d->ps) {
- [d->ps release];
- d->ps = nil;
- }
+ d->vs.release();
+ d->fs.release();
- if (d->ds) {
- [d->ds release];
- d->ds = nil;
- }
+ [d->ds release];
+ d->ds = nil;
- if (d->vsFunc) {
- [d->vsFunc release];
- d->vsFunc = nil;
- }
- if (d->vsLib) {
- [d->vsLib release];
- d->vsLib = nil;
- }
+ if (!d->ps)
+ return;
- if (d->fsFunc) {
- [d->fsFunc release];
- d->fsFunc = nil;
- }
- if (d->fsLib) {
- [d->fsLib release];
- d->fsLib = nil;
- }
+ [d->ps release];
+ d->ps = nil;
rhiD->unregisterResource(this);
}
@@ -3040,7 +3086,7 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
QShaderCode mtllib = shader.shader({ QShader::MetalLibShader, 12, shaderVariant });
if (!mtllib.shader().isEmpty()) {
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
- mtllib.shader().size(),
+ size_t(mtllib.shader().size()),
dispatch_get_global_queue(0, 0),
DISPATCH_DATA_DESTRUCTOR_DEFAULT);
NSError *err = nil;
@@ -3093,27 +3139,31 @@ bool QMetalGraphicsPipeline::build()
release();
QRHI_RES_RHI(QRhiMetal);
+ if (!rhiD->sanityCheckGraphicsPipeline(this))
+ return false;
// same binding space for vertex and constant buffers - work it around
const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, m_shaderResourceBindings)->maxBinding + 1;
MTLVertexDescriptor *inputLayout = [MTLVertexDescriptor vertexDescriptor];
- const QVector<QRhiVertexInputAttribute> attributes = m_vertexInputLayout.attributes();
- for (const QRhiVertexInputAttribute &attribute : attributes) {
- const int loc = attribute.location();
- inputLayout.attributes[loc].format = toMetalAttributeFormat(attribute.format());
- inputLayout.attributes[loc].offset = attribute.offset();
- inputLayout.attributes[loc].bufferIndex = firstVertexBinding + attribute.binding();
- }
- const QVector<QRhiVertexInputBinding> bindings = m_vertexInputLayout.bindings();
- for (int i = 0, ie = bindings.count(); i != ie; ++i) {
- const QRhiVertexInputBinding &binding(bindings[i]);
- const int layoutIdx = firstVertexBinding + i;
+ for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
+ it != itEnd; ++it)
+ {
+ const uint loc = uint(it->location());
+ inputLayout.attributes[loc].format = toMetalAttributeFormat(it->format());
+ inputLayout.attributes[loc].offset = NSUInteger(it->offset());
+ inputLayout.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding());
+ }
+ int bindingIndex = 0;
+ for (auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
+ it != itEnd; ++it, ++bindingIndex)
+ {
+ const uint layoutIdx = uint(firstVertexBinding + bindingIndex);
inputLayout.layouts[layoutIdx].stepFunction =
- binding.classification() == QRhiVertexInputBinding::PerInstance
+ it->classification() == QRhiVertexInputBinding::PerInstance
? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
- inputLayout.layouts[layoutIdx].stepRate = binding.instanceStepRate();
- inputLayout.layouts[layoutIdx].stride = binding.stride();
+ inputLayout.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate());
+ inputLayout.layouts[layoutIdx].stride = it->stride();
}
MTLRenderPipelineDescriptor *rpDesc = [[MTLRenderPipelineDescriptor alloc] init];
@@ -3126,34 +3176,66 @@ bool QMetalGraphicsPipeline::build()
// buffers not just the resource binding layout) so leave it at the default
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
- QString error;
- QByteArray entryPoint;
- id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
- if (!lib) {
- qWarning("MSL shader compilation failed: %s", qPrintable(error));
- return false;
- }
- id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
- if (!func) {
- qWarning("MSL function for entry point %s not found", entryPoint.constData());
- [lib release];
- return false;
- }
- switch (shaderStage.type()) {
- case QRhiShaderStage::Vertex:
- rpDesc.vertexFunction = func;
- d->vsLib = lib;
- d->vsFunc = func;
- break;
- case QRhiShaderStage::Fragment:
- rpDesc.fragmentFunction = func;
- d->fsLib = lib;
- d->fsFunc = func;
- break;
- default:
- [func release];
- [lib release];
- break;
+ auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage);
+ if (cacheIt != rhiD->d->shaderCache.constEnd()) {
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ d->vs = *cacheIt;
+ [d->vs.lib retain];
+ [d->vs.func retain];
+ rpDesc.vertexFunction = d->vs.func;
+ break;
+ case QRhiShaderStage::Fragment:
+ d->fs = *cacheIt;
+ [d->fs.lib retain];
+ [d->fs.func retain];
+ rpDesc.fragmentFunction = d->fs.func;
+ break;
+ default:
+ break;
+ }
+ } else {
+ QString error;
+ QByteArray entryPoint;
+ id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
+ if (!lib) {
+ qWarning("MSL shader compilation failed: %s", qPrintable(error));
+ return false;
+ }
+ id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
+ if (!func) {
+ qWarning("MSL function for entry point %s not found", entryPoint.constData());
+ [lib release];
+ return false;
+ }
+ if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
+ // Use the simplest strategy: too many cached shaders -> drop them all.
+ for (QMetalShader &s : rhiD->d->shaderCache)
+ s.release();
+ rhiD->d->shaderCache.clear();
+ }
+ switch (shaderStage.type()) {
+ case QRhiShaderStage::Vertex:
+ d->vs.lib = lib;
+ d->vs.func = func;
+ rhiD->d->shaderCache.insert(shaderStage, d->vs);
+ [d->vs.lib retain];
+ [d->vs.func retain];
+ rpDesc.vertexFunction = func;
+ break;
+ case QRhiShaderStage::Fragment:
+ d->fs.lib = lib;
+ d->fs.func = func;
+ rhiD->d->shaderCache.insert(shaderStage, d->fs);
+ [d->fs.lib retain];
+ [d->fs.func retain];
+ rpDesc.fragmentFunction = func;
+ break;
+ default:
+ [func release];
+ [lib release];
+ break;
+ }
}
}
@@ -3168,8 +3250,8 @@ bool QMetalGraphicsPipeline::build()
Q_ASSERT(m_targetBlends.count() == rpD->colorAttachmentCount
|| (m_targetBlends.isEmpty() && rpD->colorAttachmentCount == 1));
- for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
- const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
+ for (uint i = 0, ie = uint(m_targetBlends.count()); i != ie; ++i) {
+ const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[int(i)]);
rpDesc.colorAttachments[i].pixelFormat = MTLPixelFormat(rpD->colorFormat[i]);
rpDesc.colorAttachments[i].blendingEnabled = b.enable;
rpDesc.colorAttachments[i].sourceRGBBlendFactor = toMetalBlendFactor(b.srcColor);
@@ -3191,7 +3273,7 @@ bool QMetalGraphicsPipeline::build()
rpDesc.stencilAttachmentPixelFormat = fmt;
}
- rpDesc.sampleCount = rhiD->effectiveSampleCount(m_sampleCount);
+ rpDesc.sampleCount = NSUInteger(rhiD->effectiveSampleCount(m_sampleCount));
NSError *err = nil;
d->ps = [rhiD->d->dev newRenderPipelineStateWithDescriptor: rpDesc error: &err];
@@ -3253,22 +3335,13 @@ void QMetalComputePipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
- if (d->csFunc) {
- [d->csFunc release];
- d->csFunc = nil;
- }
- if (d->csLib) {
- [d->csLib release];
- d->csLib = nil;
- }
+ d->cs.release();
if (!d->ps)
return;
- if (d->ps) {
- [d->ps release];
- d->ps = nil;
- }
+ [d->ps release];
+ d->ps = nil;
rhiD->unregisterResource(this);
}
@@ -3280,28 +3353,44 @@ bool QMetalComputePipeline::build()
QRHI_RES_RHI(QRhiMetal);
- const QShader shader = m_shaderStage.shader();
- QString error;
- QByteArray entryPoint;
- id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
- &error, &entryPoint);
- if (!lib) {
- qWarning("MSL shader compilation failed: %s", qPrintable(error));
- return false;
- }
- id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
- if (!func) {
- qWarning("MSL function for entry point %s not found", entryPoint.constData());
- [lib release];
- return false;
+ auto cacheIt = rhiD->d->shaderCache.constFind(m_shaderStage);
+ if (cacheIt != rhiD->d->shaderCache.constEnd()) {
+ d->cs = *cacheIt;
+ } else {
+ const QShader shader = m_shaderStage.shader();
+ QString error;
+ QByteArray entryPoint;
+ id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
+ &error, &entryPoint);
+ if (!lib) {
+ qWarning("MSL shader compilation failed: %s", qPrintable(error));
+ return false;
+ }
+ id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
+ if (!func) {
+ qWarning("MSL function for entry point %s not found", entryPoint.constData());
+ [lib release];
+ return false;
+ }
+ d->cs.lib = lib;
+ d->cs.func = func;
+ d->cs.localSize = shader.description().computeShaderLocalSize();
+
+ if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
+ for (QMetalShader &s : rhiD->d->shaderCache)
+ s.release();
+ rhiD->d->shaderCache.clear();
+ }
+ rhiD->d->shaderCache.insert(m_shaderStage, d->cs);
}
- d->csLib = lib;
- d->csFunc = func;
- std::array<uint, 3> localSize = shader.description().computeShaderLocalSize();
- d->localSize = MTLSizeMake(localSize[0], localSize[1], localSize[2]);
+
+ [d->cs.lib retain];
+ [d->cs.func retain];
+
+ d->localSize = MTLSizeMake(d->cs.localSize[0], d->cs.localSize[1], d->cs.localSize[2]);
NSError *err = nil;
- d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->csFunc error: &err];
+ d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->cs.func error: &err];
if (!d->ps) {
const QString msg = QString::fromNSString(err.localizedDescription);
qWarning("Failed to create render pipeline state: %s", qPrintable(msg));
@@ -3364,6 +3453,10 @@ void QMetalCommandBuffer::resetPerPassCachedState()
currentSrbGeneration = 0;
currentResSlot = -1;
currentIndexBuffer = nullptr;
+ currentIndexOffset = 0;
+ currentIndexFormat = QRhiCommandBuffer::IndexUInt16;
+ currentCullMode = -1;
+ currentFrontFaceWinding = -1;
d->currentFirstVertexBinding = -1;
d->currentVertexInputsBuffers.clear();
@@ -3432,17 +3525,8 @@ QRhiRenderTarget *QMetalSwapChain::currentFrameRenderTarget()
QSize QMetalSwapChain::surfacePixelSize()
{
- // may be called before build, must not access other than m_*
-
- NSView *v = (NSView *) m_window->winId();
- if (v) {
- CAMetalLayer *layer = (CAMetalLayer *) [v layer];
- if (layer) {
- CGSize size = [layer drawableSize];
- return QSize(size.width, size.height);
- }
- }
- return QSize();
+ Q_ASSERT(m_window);
+ return m_window->size() * m_window->devicePixelRatio();
}
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
@@ -3454,7 +3538,7 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
rpD->colorAttachmentCount = 1;
rpD->hasDepthStencil = m_depthStencil != nullptr;
- rpD->colorFormat[0] = d->colorFormat;
+ rpD->colorFormat[0] = int(d->colorFormat);
// m_depthStencil may not be built yet so cannot rely on computed fields in it
rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
@@ -3493,8 +3577,9 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
- NSView *v = (NSView *) window->winId();
- d->layer = (CAMetalLayer *) [v layer];
+ NSView *view = reinterpret_cast<NSView *>(window->winId());
+ Q_ASSERT(view);
+ d->layer = static_cast<CAMetalLayer *>(view.layer);
Q_ASSERT(d->layer);
chooseFormats();
@@ -3511,7 +3596,27 @@ bool QMetalSwapChain::buildOrResize()
}
#endif
- m_currentPixelSize = surfacePixelSize();
+ if (m_flags.testFlag(SurfaceHasPreMulAlpha)) {
+ d->layer.opaque = NO;
+ } else if (m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
+ // The CoreAnimation compositor is said to expect premultiplied alpha,
+ // so this is then wrong when it comes to the blending operations but
+ // there's nothing we can do. Fortunately Qt Quick always outputs
+ // premultiplied alpha so it is not a problem there.
+ d->layer.opaque = NO;
+ } else {
+ d->layer.opaque = YES;
+ }
+
+ // Now set the layer's drawableSize which will stay set to the same value
+ // until the next buildOrResize(), thus ensuring atomicity with regards to
+ // the drawable size in frames.
+ CGSize layerSize = d->layer.bounds.size;
+ layerSize.width *= d->layer.contentsScale;
+ layerSize.height *= d->layer.contentsScale;
+ d->layer.drawableSize = layerSize;
+
+ m_currentPixelSize = QSizeF::fromCGSize(layerSize).toSize();
pixelSize = m_currentPixelSize;
[d->layer setDevice: rhiD->d->dev];
@@ -3532,13 +3637,20 @@ bool QMetalSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
- qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
- m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
- pixelSize.width(), pixelSize.height());
+ if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
+ m_depthStencil->setPixelSize(pixelSize);
+ if (!m_depthStencil->build())
+ qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
+ pixelSize.width(), pixelSize.height());
+ } else {
+ qWarning("Depth-stencil buffer's size (%dx%d) does not match the layer size (%dx%d). Expect problems.",
+ m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
+ pixelSize.width(), pixelSize.height());
+ }
}
rtWrapper.d->pixelSize = pixelSize;
- rtWrapper.d->dpr = window->devicePixelRatio();
+ rtWrapper.d->dpr = float(window->devicePixelRatio());
rtWrapper.d->sampleCount = samples;
rtWrapper.d->colorAttCount = 1;
rtWrapper.d->dsAttCount = ds ? 1 : 0;
@@ -3549,9 +3661,9 @@ bool QMetalSwapChain::buildOrResize()
MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init];
desc.textureType = MTLTextureType2DMultisample;
desc.pixelFormat = d->colorFormat;
- desc.width = pixelSize.width();
- desc.height = pixelSize.height();
- desc.sampleCount = samples;
+ desc.width = NSUInteger(pixelSize.width());
+ desc.height = NSUInteger(pixelSize.height());
+ desc.sampleCount = NSUInteger(samples);
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget;
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
index c448865f4d..688fec8147 100644
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ b/src/gui/rhi/qrhimetal_p_p.h
@@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
- QVector<QRhiShaderResourceBinding> sortedBindings;
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
@@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
- QVector<BoundResourceData> boundResourceData;
+ QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;
@@ -271,8 +271,11 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer
ComputePass
};
+ // per-pass (render or compute command encoder) persistent state
PassType recordingPass;
QRhiRenderTarget *currentTarget;
+
+ // per-pass (render or compute command encoder) volatile (cached) state
QRhiGraphicsPipeline *currentGraphicsPipeline;
QRhiComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
@@ -283,6 +286,8 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer
QRhiBuffer *currentIndexBuffer;
quint32 currentIndexOffset;
QRhiCommandBuffer::IndexFormat currentIndexFormat;
+ int currentCullMode;
+ int currentFrontFaceWinding;
const QRhiNativeHandles *nativeHandles();
void resetState();
@@ -416,7 +421,9 @@ public:
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
- void makeThreadLocalNativeContextCurrent() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp
index dff6e05268..fe606f971f 100644
--- a/src/gui/rhi/qrhinull.cpp
+++ b/src/gui/rhi/qrhinull.cpp
@@ -36,6 +36,7 @@
#include "qrhinull_p_p.h"
#include <qmath.h>
+#include <QPainter>
QT_BEGIN_NAMESPACE
@@ -169,11 +170,22 @@ void QRhiNull::sendVMemStatsToProfiler()
// nothing to do here
}
-void QRhiNull::makeThreadLocalNativeContextCurrent()
+bool QRhiNull::makeThreadLocalNativeContextCurrent()
+{
+ // not applicable
+ return false;
+}
+
+void QRhiNull::releaseCachedResources()
{
// nothing to do here
}
+bool QRhiNull::isDeviceLost() const
+{
+ return false;
+}
+
QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
@@ -374,27 +386,125 @@ QRhi::FrameOpResult QRhiNull::finish()
return QRhi::FrameOpSuccess;
}
+void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
+{
+ QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
+ for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
+ for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level])) {
+ if (!subresDesc.image().isNull()) {
+ const QImage src = subresDesc.image();
+ QPainter painter(&texD->image[layer][level]);
+ const QSize srcSize = subresDesc.sourceSize().isEmpty()
+ ? src.size() : subresDesc.sourceSize();
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.drawImage(subresDesc.destinationTopLeft(), src,
+ QRect(subresDesc.sourceTopLeft(), srcSize));
+ } else if (!subresDesc.data().isEmpty()) {
+ const QSize subresSize = q->sizeForMipLevel(level, texD->pixelSize());
+ int w = subresSize.width();
+ int h = subresSize.height();
+ if (!subresDesc.sourceSize().isEmpty()) {
+ w = subresDesc.sourceSize().width();
+ h = subresDesc.sourceSize().height();
+ }
+ // sourceTopLeft is not supported on this path as per QRhi docs
+ const char *src = subresDesc.data().constData();
+ const int srcBpl = w * 4;
+ const QPoint dstOffset = subresDesc.destinationTopLeft();
+ uchar *dst = texD->image[layer][level].bits();
+ const int dstBpl = texD->image[layer][level].bytesPerLine();
+ for (int y = 0; y < h; ++y) {
+ memcpy(dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl,
+ src + y * srcBpl,
+ size_t(srcBpl));
+ }
+ }
+ }
+ }
+ }
+}
+
+void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
+{
+ QNullTexture *srcD = QRHI_RES(QNullTexture, u.src);
+ QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst);
+ const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]);
+ QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]);
+ const QPoint dstPos = u.desc.destinationTopLeft();
+ const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize();
+ const QPoint srcPos = u.desc.sourceTopLeft();
+
+ QPainter painter(&dstImage);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size));
+}
+
+void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
+{
+ QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
+ const QSize baseSize = texD->pixelSize();
+ const int levelCount = q->mipLevelsForSize(baseSize);
+ for (int level = 1; level < levelCount; ++level)
+ texD->image[0][level] = texD->image[0][0].scaled(q->sizeForMipLevel(level, baseSize));
+}
+
void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
{
Q_UNUSED(cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
+ if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
+ || u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
+ {
+ QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
+ memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size()));
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
+ QRhiBufferReadbackResult *result = u.result;
+ result->data.resize(u.readSize);
+ QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
+ memcpy(result->data.data(), bufD->data.constData() + u.offset, size_t(u.readSize));
+ if (result->completed)
+ result->completed();
+ }
+ }
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
- if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
- QRhiReadbackResult *result = u.read.result;
- QRhiTexture *tex = u.read.rb.texture();
- if (tex) {
- result->format = tex->format();
- result->pixelSize = q->sizeForMipLevel(u.read.rb.level(), tex->pixelSize());
+ if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
+ if (u.dst->format() == QRhiTexture::RGBA8)
+ simulateTextureUpload(u);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
+ if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8)
+ simulateTextureCopy(u);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
+ QRhiReadbackResult *result = u.result;
+ QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture());
+ if (texD) {
+ result->format = texD->format();
+ result->pixelSize = q->sizeForMipLevel(u.rb.level(), texD->pixelSize());
} else {
Q_ASSERT(currentSwapChain);
result->format = QRhiTexture::RGBA8;
result->pixelSize = currentSwapChain->currentPixelSize();
}
+ quint32 bytesPerLine = 0;
quint32 byteSize = 0;
- textureFormatInfo(result->format, result->pixelSize, nullptr, &byteSize);
- result->data.fill(0, byteSize);
+ textureFormatInfo(result->format, result->pixelSize, &bytesPerLine, &byteSize);
+ if (texD && texD->format() == QRhiTexture::RGBA8) {
+ result->data.resize(int(byteSize));
+ const QImage &src(texD->image[u.rb.layer()][u.rb.level()]);
+ char *dst = result->data.data();
+ for (int y = 0, h = src.height(); y < h; ++y) {
+ memcpy(dst, src.constScanLine(y), bytesPerLine);
+ dst += bytesPerLine;
+ }
+ } else {
+ result->data.fill(0, int(byteSize));
+ }
if (result->completed)
result->completed();
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
+ if (u.dst->format() == QRhiTexture::RGBA8)
+ simulateTextureGenMips(u);
}
}
ud->free();
@@ -443,14 +553,18 @@ QNullBuffer::~QNullBuffer()
void QNullBuffer::release()
{
+ data.clear();
+
QRHI_PROF;
QRHI_PROF_F(releaseBuffer(this));
}
bool QNullBuffer::build()
{
+ data.fill('\0', m_size);
+
QRHI_PROF;
- QRHI_PROF_F(newBuffer(this, m_size, 1, 0));
+ QRHI_PROF_F(newBuffer(this, uint(m_size), 1, 0));
return true;
}
@@ -502,22 +616,36 @@ void QNullTexture::release()
bool QNullTexture::build()
{
+ QRHI_RES_RHI(QRhiNull);
const bool isCube = m_flags.testFlag(CubeMap);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
- const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
+ const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
+ const int layerCount = isCube ? 6 : 1;
+
+ if (m_format == RGBA8) {
+ for (int layer = 0; layer < layerCount; ++layer) {
+ for (int level = 0; level < mipLevelCount; ++level) {
+ image[layer][level] = QImage(rhiD->q->sizeForMipLevel(level, size),
+ QImage::Format_RGBA8888_Premultiplied);
+ image[layer][level].fill(Qt::yellow);
+ }
+ }
+ }
+
QRHI_PROF;
- QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, 1));
+ QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1));
return true;
}
bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
{
Q_UNUSED(src);
+ QRHI_RES_RHI(QRhiNull);
const bool isCube = m_flags.testFlag(CubeMap);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
- const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
+ const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
QRHI_PROF;
QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
return true;
@@ -617,10 +745,9 @@ QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescr
bool QNullTextureRenderTarget::build()
{
d.rp = QRHI_RES(QNullRenderPassDescriptor, m_renderPassDesc);
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
- if (!colorAttachments.isEmpty()) {
- QRhiTexture *tex = colorAttachments.first().texture();
- QRhiRenderBuffer *rb = colorAttachments.first().renderBuffer();
+ if (m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments()) {
+ QRhiTexture *tex = m_desc.cbeginColorAttachments()->texture();
+ QRhiRenderBuffer *rb = m_desc.cbeginColorAttachments()->renderBuffer();
d.pixelSize = tex ? tex->pixelSize() : rb->pixelSize();
} else if (m_desc.depthStencilBuffer()) {
d.pixelSize = m_desc.depthStencilBuffer()->pixelSize();
@@ -680,6 +807,10 @@ void QNullGraphicsPipeline::release()
bool QNullGraphicsPipeline::build()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (!rhiD->sanityCheckGraphicsPipeline(this))
+ return false;
+
return true;
}
diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h
index bdf0d59724..ce517bfa63 100644
--- a/src/gui/rhi/qrhinull_p_p.h
+++ b/src/gui/rhi/qrhinull_p_p.h
@@ -59,6 +59,8 @@ struct QNullBuffer : public QRhiBuffer
~QNullBuffer();
void release() override;
bool build() override;
+
+ QByteArray data;
};
struct QNullRenderBuffer : public QRhiRenderBuffer
@@ -82,6 +84,7 @@ struct QNullTexture : public QRhiTexture
const QRhiNativeHandles *nativeHandles() override;
QRhiNullTextureNativeHandles nativeHandlesStruct;
+ QImage image[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
};
struct QNullSampler : public QRhiSampler
@@ -282,7 +285,13 @@ public:
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
- void makeThreadLocalNativeContextCurrent() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
+ void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
+ void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
QRhiNullNativeHandles nativeHandlesStruct;
QRhiSwapChain *currentSwapChain = nullptr;
diff --git a/src/gui/rhi/qrhiprofiler.cpp b/src/gui/rhi/qrhiprofiler.cpp
index e74e446a1c..1521c0f36e 100644
--- a/src/gui/rhi/qrhiprofiler.cpp
+++ b/src/gui/rhi/qrhiprofiler.cpp
@@ -319,7 +319,7 @@ void QRhiProfilerPrivate::writeFloat(const char *key, float f)
Q_ASSERT(key[0] == 'F');
buf.append(key);
buf.append(',');
- buf.append(QByteArray::number(f));
+ buf.append(QByteArray::number(double(f)));
buf.append(',');
}
@@ -385,7 +385,7 @@ void QRhiProfilerPrivate::newRenderBuffer(QRhiRenderBuffer *rb, bool transientBa
const QRhiTexture::Format assumedFormat = type == QRhiRenderBuffer::DepthStencil ? QRhiTexture::D32F : QRhiTexture::RGBA8;
quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(assumedFormat, sz, 1, 1);
if (sampleCount > 1)
- byteSize *= sampleCount;
+ byteSize *= uint(sampleCount);
startEntry(QRhiProfiler::NewRenderBuffer, ts.elapsed(), rb);
writeInt("type", type);
@@ -416,7 +416,7 @@ void QRhiProfilerPrivate::newTexture(QRhiTexture *tex, bool owns, int mipCount,
const QSize sz = tex->pixelSize();
quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(format, sz, mipCount, layerCount);
if (sampleCount > 1)
- byteSize *= sampleCount;
+ byteSize *= uint(sampleCount);
startEntry(QRhiProfiler::NewTexture, ts.elapsed(), tex);
writeInt("width", sz.width());
@@ -467,7 +467,7 @@ void QRhiProfilerPrivate::resizeSwapChain(QRhiSwapChain *sc, int bufferCount, in
const QSize sz = sc->currentPixelSize();
quint32 byteSize = rhiDWhenEnabled->approxByteSizeForTexture(QRhiTexture::BGRA8, sz, 1, 1);
- byteSize = byteSize * bufferCount + byteSize * msaaBufferCount * sampleCount;
+ byteSize = byteSize * uint(bufferCount) + byteSize * uint(msaaBufferCount) * uint(sampleCount);
startEntry(QRhiProfiler::ResizeSwapChain, ts.elapsed(), sc);
writeInt("width", sz.width());
@@ -569,7 +569,7 @@ void QRhiProfilerPrivate::swapChainFrameGpuTime(QRhiSwapChain *sc, float gpuTime
}
}
-void QRhiProfilerPrivate::newReadbackBuffer(quint64 id, QRhiResource *src, quint32 size)
+void QRhiProfilerPrivate::newReadbackBuffer(qint64 id, QRhiResource *src, quint32 size)
{
if (!outputDevice)
return;
@@ -580,7 +580,7 @@ void QRhiProfilerPrivate::newReadbackBuffer(quint64 id, QRhiResource *src, quint
endEntry();
}
-void QRhiProfilerPrivate::releaseReadbackBuffer(quint64 id)
+void QRhiProfilerPrivate::releaseReadbackBuffer(qint64 id)
{
if (!outputDevice)
return;
@@ -590,7 +590,7 @@ void QRhiProfilerPrivate::releaseReadbackBuffer(quint64 id)
endEntry();
}
-void QRhiProfilerPrivate::vmemStat(int realAllocCount, int subAllocCount, quint32 totalSize, quint32 unusedSize)
+void QRhiProfilerPrivate::vmemStat(uint realAllocCount, uint subAllocCount, quint32 totalSize, quint32 unusedSize)
{
if (!outputDevice)
return;
diff --git a/src/gui/rhi/qrhiprofiler_p_p.h b/src/gui/rhi/qrhiprofiler_p_p.h
index 49c6bd78ed..7d0f183fb1 100644
--- a/src/gui/rhi/qrhiprofiler_p_p.h
+++ b/src/gui/rhi/qrhiprofiler_p_p.h
@@ -79,10 +79,10 @@ public:
void endSwapChainFrame(QRhiSwapChain *sc, int frameCount);
void swapChainFrameGpuTime(QRhiSwapChain *sc, float gpuTimeMs);
- void newReadbackBuffer(quint64 id, QRhiResource *src, quint32 size);
- void releaseReadbackBuffer(quint64 id);
+ void newReadbackBuffer(qint64 id, QRhiResource *src, quint32 size);
+ void releaseReadbackBuffer(qint64 id);
- void vmemStat(int realAllocCount, int subAllocCount, quint32 totalSize, quint32 unusedSize);
+ void vmemStat(uint realAllocCount, uint subAllocCount, quint32 totalSize, quint32 unusedSize);
void startEntry(QRhiProfiler::StreamOp op, qint64 timestamp, QRhiResource *res);
void writeInt(const char *key, qint64 v);
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index dfc85fb853..2d69abb36b 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -211,7 +211,8 @@ QT_BEGIN_NAMESPACE
\brief Holds the Vulkan render pass object backing a QRhiRenderPassDescriptor.
*/
-static inline VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)
+template <class Int>
+inline Int aligned(Int v, Int byteAlign)
{
return (v + byteAlign - 1) & ~(byteAlign - 1);
}
@@ -362,6 +363,11 @@ bool QRhiVulkan::create(QRhi::Flags flags)
Q_UNUSED(flags);
Q_ASSERT(inst);
+ if (!inst->isValid()) {
+ qWarning("Vulkan instance is not valid");
+ return false;
+ }
+
globalVulkanInstance = inst; // assume this will not change during the lifetime of the entire application
f = inst->functions();
@@ -370,7 +376,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
auto queryQueueFamilyProps = [this, &queueFamilyProps] {
uint32_t queueCount = 0;
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
- queueFamilyProps.resize(queueCount);
+ queueFamilyProps.resize(int(queueCount));
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
};
@@ -387,22 +393,42 @@ bool QRhiVulkan::create(QRhi::Flags flags)
qWarning("Failed to enumerate physical devices: %d", err);
return false;
}
+
int physDevIndex = -1;
int requestedPhysDevIndex = -1;
if (qEnvironmentVariableIsSet("QT_VK_PHYSICAL_DEVICE_INDEX"))
requestedPhysDevIndex = qEnvironmentVariableIntValue("QT_VK_PHYSICAL_DEVICE_INDEX");
- for (uint32_t i = 0; i < physDevCount; ++i) {
+
+ if (requestedPhysDevIndex < 0 && flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ for (int i = 0; i < int(physDevCount); ++i) {
+ f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
+ if (physDevProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
+ requestedPhysDevIndex = i;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < int(physDevCount); ++i) {
f->vkGetPhysicalDeviceProperties(physDevs[i], &physDevProperties);
- qCDebug(QRHI_LOG_INFO, "Physical device %d: '%s' %d.%d.%d", i,
+ qCDebug(QRHI_LOG_INFO, "Physical device %d: '%s' %d.%d.%d (api %d.%d.%d vendor 0x%X device 0x%X type %d)",
+ i,
physDevProperties.deviceName,
VK_VERSION_MAJOR(physDevProperties.driverVersion),
VK_VERSION_MINOR(physDevProperties.driverVersion),
- VK_VERSION_PATCH(physDevProperties.driverVersion));
+ VK_VERSION_PATCH(physDevProperties.driverVersion),
+ VK_VERSION_MAJOR(physDevProperties.apiVersion),
+ VK_VERSION_MINOR(physDevProperties.apiVersion),
+ VK_VERSION_PATCH(physDevProperties.apiVersion),
+ physDevProperties.vendorID,
+ physDevProperties.deviceID,
+ physDevProperties.deviceType);
if (physDevIndex < 0 && (requestedPhysDevIndex < 0 || requestedPhysDevIndex == int(i))) {
physDevIndex = i;
qCDebug(QRHI_LOG_INFO, " using this physical device");
}
}
+
if (physDevIndex < 0) {
qWarning("No matching physical device");
return false;
@@ -423,7 +449,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount);
if (gfxQueueFamilyIdx == -1
&& (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
- && (!maybeWindow || inst->supportsPresent(physDev, i, maybeWindow)))
+ && (!maybeWindow || inst->supportsPresent(physDev, uint32_t(i), maybeWindow)))
{
if (queueFamilyProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
gfxQueueFamilyIdx = i;
@@ -444,7 +470,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
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].queueFamilyIndex = uint32_t(gfxQueueFamilyIdx);
queueInfo[0].queueCount = 1;
queueInfo[0].pQueuePriorities = prio;
@@ -480,9 +506,9 @@ bool QRhiVulkan::create(QRhi::Flags flags)
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
devInfo.queueCreateInfoCount = 1;
devInfo.pQueueCreateInfos = queueInfo;
- devInfo.enabledLayerCount = devLayers.count();
+ devInfo.enabledLayerCount = uint32_t(devLayers.count());
devInfo.ppEnabledLayerNames = devLayers.constData();
- devInfo.enabledExtensionCount = requestedDevExts.count();
+ devInfo.enabledExtensionCount = uint32_t(requestedDevExts.count());
devInfo.ppEnabledExtensionNames = requestedDevExts.constData();
err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
@@ -498,7 +524,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
VkCommandPoolCreateInfo poolInfo;
memset(&poolInfo, 0, sizeof(poolInfo));
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
+ poolInfo.queueFamilyIndex = uint32_t(gfxQueueFamilyIdx);
VkResult err = df->vkCreateCommandPool(dev, &poolInfo, nullptr, &cmdPool);
if (err != VK_SUCCESS) {
qWarning("Failed to create command pool: %d", err);
@@ -508,7 +534,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
if (gfxQueueFamilyIdx != -1) {
if (!gfxQueue)
- df->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
+ df->vkGetDeviceQueue(dev, uint32_t(gfxQueueFamilyIdx), 0, &gfxQueue);
if (queueFamilyProps.isEmpty())
queryQueueFamilyProps();
@@ -547,6 +573,9 @@ bool QRhiVulkan::create(QRhi::Flags flags)
VmaAllocatorCreateInfo allocatorInfo;
memset(&allocatorInfo, 0, sizeof(allocatorInfo));
+ // A QRhi is supposed to be used from one single thread only. Disable
+ // the allocator's own mutexes. This gives a performance boost.
+ allocatorInfo.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
allocatorInfo.physicalDevice = physDev;
allocatorInfo.device = dev;
allocatorInfo.pVulkanFunctions = &afuncs;
@@ -588,6 +617,8 @@ bool QRhiVulkan::create(QRhi::Flags flags)
vkDebugMarkerSetObjectName = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(f->vkGetDeviceProcAddr(dev, "vkDebugMarkerSetObjectNameEXT"));
}
+ deviceLost = false;
+
nativeHandlesStruct.physDev = physDev;
nativeHandlesStruct.dev = dev;
nativeHandlesStruct.gfxQueueFamilyIdx = gfxQueueFamilyIdx;
@@ -603,7 +634,8 @@ void QRhiVulkan::destroy()
if (!df)
return;
- df->vkDeviceWaitIdle(dev);
+ if (!deviceLost)
+ df->vkDeviceWaitIdle(dev);
executeDeferredReleases(true);
finishActiveReadbacks(true);
@@ -691,7 +723,7 @@ bool QRhiVulkan::allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, V
df->vkResetDescriptorPool(dev, descriptorPools[i].pool, 0);
descriptorPools[i].allocedDescSets = 0;
}
- if (descriptorPools[i].allocedDescSets + allocInfo->descriptorSetCount <= QVK_DESC_SETS_PER_POOL) {
+ if (descriptorPools[i].allocedDescSets + int(allocInfo->descriptorSetCount) <= QVK_DESC_SETS_PER_POOL) {
VkResult err = tryAllocate(i);
if (err == VK_SUCCESS) {
descriptorPools[i].allocedDescSets += allocInfo->descriptorSetCount;
@@ -901,8 +933,8 @@ bool QRhiVulkan::createTransientImage(VkFormat format,
imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imgInfo.imageType = VK_IMAGE_TYPE_2D;
imgInfo.format = format;
- imgInfo.extent.width = pixelSize.width();
- imgInfo.extent.height = pixelSize.height();
+ imgInfo.extent.width = uint32_t(pixelSize.width());
+ imgInfo.extent.height = uint32_t(pixelSize.height());
imgInfo.extent.depth = 1;
imgInfo.mipLevels = imgInfo.arrayLayers = 1;
imgInfo.samples = samples;
@@ -925,7 +957,7 @@ bool QRhiVulkan::createTransientImage(VkFormat format,
VkMemoryAllocateInfo memInfo;
memset(&memInfo, 0, sizeof(memInfo));
memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * count;
+ memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * VkDeviceSize(count);
uint32_t startIndex = 0;
do {
@@ -1087,7 +1119,8 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil,
}
bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
- const QVector<QRhiColorAttachment> &colorAttachments,
+ const QRhiColorAttachment *firstColorAttachment,
+ const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
bool preserveDs,
QRhiRenderBuffer *depthStencilBuffer,
@@ -1096,13 +1129,12 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
QVarLengthArray<VkAttachmentDescription, 8> attDescs;
QVarLengthArray<VkAttachmentReference, 8> colorRefs;
QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
- const int colorAttCount = colorAttachments.count();
// attachment list layout is color (0-8), ds (0-1), resolve (0-8)
- for (int i = 0; i < colorAttCount; ++i) {
- QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachments[i].texture());
- QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachments[i].renderBuffer());
+ for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
+ QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
const VkFormat vkformat = texD ? texD->vkformat : rbD->vkformat;
const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
@@ -1112,7 +1144,7 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
attDesc.format = vkformat;
attDesc.samples = samples;
attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc.storeOp = colorAttachments[i].resolveTexture() ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
+ attDesc.storeOp = it->resolveTexture() ? 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;
// this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT
@@ -1146,9 +1178,9 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
}
VkAttachmentReference dsRef = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
- for (int i = 0; i < colorAttCount; ++i) {
- if (colorAttachments[i].resolveTexture()) {
- QVkTexture *rtexD = QRHI_RES(QVkTexture, colorAttachments[i].resolveTexture());
+ for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ if (it->resolveTexture()) {
+ QVkTexture *rtexD = QRHI_RES(QVkTexture, it->resolveTexture());
if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
qWarning("Resolving into a multisample texture is not supported");
@@ -1175,7 +1207,7 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
VkSubpassDescription subpassDesc;
memset(&subpassDesc, 0, sizeof(subpassDesc));
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpassDesc.colorAttachmentCount = colorRefs.count();
+ subpassDesc.colorAttachmentCount = uint32_t(colorRefs.count());
Q_ASSERT(colorRefs.count() == resolveRefs.count());
subpassDesc.pColorAttachments = !colorRefs.isEmpty() ? colorRefs.constData() : nullptr;
subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr;
@@ -1184,7 +1216,7 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
VkRenderPassCreateInfo rpInfo;
memset(&rpInfo, 0, sizeof(rpInfo));
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- rpInfo.attachmentCount = attDescs.count();
+ rpInfo.attachmentCount = uint32_t(attDescs.count());
rpInfo.pAttachments = attDescs.constData();
rpInfo.subpassCount = 1;
rpInfo.pSubpasses = &subpassDesc;
@@ -1325,7 +1357,7 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
}
if (actualSwapChainBufferCount != reqBufferCount)
qCDebug(QRHI_LOG_INFO, "Actual swapchain buffer count is %u", actualSwapChainBufferCount);
- swapChainD->bufferCount = actualSwapChainBufferCount;
+ swapChainD->bufferCount = int(actualSwapChainBufferCount);
VkImage swapChainImages[QVkSwapChain::MAX_BUFFER_COUNT];
err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, swapChainImages);
@@ -1424,7 +1456,8 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain)
if (swapChainD->sc == VK_NULL_HANDLE)
return;
- df->vkDeviceWaitIdle(dev);
+ if (!deviceLost)
+ df->vkDeviceWaitIdle(dev);
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) {
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[i]);
@@ -1487,15 +1520,6 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain)
// NB! surface and similar must remain intact
}
-static inline bool checkDeviceLost(VkResult err)
-{
- if (err == VK_ERROR_DEVICE_LOST) {
- qWarning("Device lost");
- return true;
- }
- return false;
-}
-
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
QVkSwapChain *swapChainD = QRHI_RES(QVkSwapChain, swapChain);
@@ -1522,10 +1546,12 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
} else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
return QRhi::FrameOpSwapChainOutOfDate;
} else {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkAcquireNextImageKHR()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to acquire next swapchain image: %d", err);
+ }
+ qWarning("Failed to acquire next swapchain image: %d", err);
return QRhi::FrameOpError;
}
}
@@ -1540,12 +1566,12 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// will make B wait for A's frame 0 commands, so if a resource is written
// in B's frame or when B checks for pending resource releases, that won't
// mess up A's in-flight commands (as they are not in flight anymore).
- waitCommandCompletion(swapChainD->currentFrameSlot);
+ waitCommandCompletion(int(swapChainD->currentFrameSlot));
// Now is the time to read the timestamps for the previous frame for this slot.
if (frame.timestampQueryIndex >= 0) {
quint64 timestamp[2] = { 0, 0 };
- VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, frame.timestampQueryIndex, 2,
+ VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame.timestampQueryIndex), 2,
2 * sizeof(quint64), timestamp, sizeof(quint64),
VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
@@ -1585,10 +1611,10 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
}
}
if (timestampQueryIdx >= 0) {
- df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, timestampQueryIdx, 2);
+ df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
// record timestamp at the start of the command buffer
df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- timestampQueryPool, timestampQueryIdx);
+ timestampQueryPool, uint32_t(timestampQueryIdx));
frame.timestampQueryIndex = timestampQueryIdx;
}
@@ -1598,7 +1624,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
swapChainD->rtWrapper.d.fb = image.fb;
- currentFrameSlot = swapChainD->currentFrameSlot;
+ currentFrameSlot = int(swapChainD->currentFrameSlot);
currentSwapChain = swapChainD;
if (swapChainD->ds)
swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
@@ -1653,7 +1679,7 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
// record another timestamp, when enabled
if (frame.timestampQueryIndex >= 0) {
df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
- timestampQueryPool, frame.timestampQueryIndex + 1);
+ timestampQueryPool, uint32_t(frame.timestampQueryIndex + 1));
}
// stop recording and submit to the queue
@@ -1684,15 +1710,21 @@ 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) {
return QRhi::FrameOpSwapChainOutOfDate;
} else if (err != VK_SUBOPTIMAL_KHR) {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkQueuePresentKHR()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to present: %d", err);
+ }
+ qWarning("Failed to present: %d", err);
return QRhi::FrameOpError;
}
}
@@ -1749,10 +1781,12 @@ QRhi::FrameOpResult QRhiVulkan::startPrimaryCommandBuffer(VkCommandBuffer *cb)
VkResult err = df->vkAllocateCommandBuffers(dev, &cmdBufInfo, cb);
if (err != VK_SUCCESS) {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkAllocateCommandBuffers()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to allocate frame command buffer: %d", err);
+ }
+ qWarning("Failed to allocate frame command buffer: %d", err);
return QRhi::FrameOpError;
}
@@ -1762,10 +1796,12 @@ QRhi::FrameOpResult QRhiVulkan::startPrimaryCommandBuffer(VkCommandBuffer *cb)
err = df->vkBeginCommandBuffer(*cb, &cmdBufBeginInfo);
if (err != VK_SUCCESS) {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkBeginCommandBuffer()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to begin frame command buffer: %d", err);
+ }
+ qWarning("Failed to begin frame command buffer: %d", err);
return QRhi::FrameOpError;
}
@@ -1777,10 +1813,12 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
{
VkResult err = df->vkEndCommandBuffer(cb);
if (err != VK_SUCCESS) {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkEndCommandBuffer()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to end frame command buffer: %d", err);
+ }
+ qWarning("Failed to end frame command buffer: %d", err);
return QRhi::FrameOpError;
}
@@ -1802,10 +1840,12 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
err = df->vkQueueSubmit(gfxQueue, 1, &submitInfo, cmdFence);
if (err != VK_SUCCESS) {
- if (checkDeviceLost(err))
+ if (err == VK_ERROR_DEVICE_LOST) {
+ qWarning("Device loss detected in vkQueueSubmit()");
+ deviceLost = true;
return QRhi::FrameOpDeviceLost;
- else
- qWarning("Failed to submit to graphics queue: %d", err);
+ }
+ qWarning("Failed to submit to graphics queue: %d", err);
return QRhi::FrameOpError;
}
@@ -1932,8 +1972,8 @@ static inline QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const
{
QRhiPassResourceTracker::UsageState u;
u.layout = 0; // unused with buffers
- u.access = bufUsage.access;
- u.stage = bufUsage.stage;
+ u.access = int(bufUsage.access);
+ u.stage = int(bufUsage.stage);
return u;
}
@@ -1941,8 +1981,8 @@ static inline QRhiPassResourceTracker::UsageState toPassTrackerUsageState(const
{
QRhiPassResourceTracker::UsageState u;
u.layout = texUsage.layout;
- u.access = texUsage.access;
- u.stage = texUsage.stage;
+ u.access = int(texUsage.access);
+ u.stage = int(texUsage.stage);
return u;
}
@@ -1951,11 +1991,10 @@ void QRhiVulkan::activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRe
rtD->lastActiveFrameSlot = currentFrameSlot;
rtD->d.rp->lastActiveFrameSlot = currentFrameSlot;
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
- const QVector<QRhiColorAttachment> colorAttachments = rtD->m_desc.colorAttachments();
- for (const QRhiColorAttachment &colorAttachment : colorAttachments) {
- QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachment.texture());
- QVkTexture *resolveTexD = QRHI_RES(QVkTexture, colorAttachment.resolveTexture());
- QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachment.renderBuffer());
+ for (auto it = rtD->m_desc.cbeginColorAttachments(), itEnd = rtD->m_desc.cendColorAttachments(); it != itEnd; ++it) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
+ QVkTexture *resolveTexD = QRHI_RES(QVkTexture, it->resolveTexture());
+ QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
if (texD) {
trackedRegisterTexture(&passResTracker, texD,
QRhiPassResourceTracker::TexColorOutput,
@@ -2106,8 +2145,8 @@ void QRhiVulkan::beginPass(QRhiCommandBuffer *cb,
rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpBeginInfo.renderPass = rtD->rp->rp;
rpBeginInfo.framebuffer = rtD->fb;
- rpBeginInfo.renderArea.extent.width = rtD->pixelSize.width();
- rpBeginInfo.renderArea.extent.height = rtD->pixelSize.height();
+ rpBeginInfo.renderArea.extent.width = uint32_t(rtD->pixelSize.width());
+ rpBeginInfo.renderArea.extent.height = uint32_t(rtD->pixelSize.height());
QVarLengthArray<VkClearValue, 4> cvs;
for (int i = 0; i < rtD->colorAttCount; ++i) {
@@ -2127,7 +2166,7 @@ void QRhiVulkan::beginPass(QRhiCommandBuffer *cb,
float(colorClearValue.alphaF()) } };
cvs.append(cv);
}
- rpBeginInfo.clearValueCount = cvs.count();
+ rpBeginInfo.clearValueCount = uint32_t(cvs.count());
QVkCommandBuffer::Command cmd;
cmd.cmd = QVkCommandBuffer::Command::BeginRenderPass;
@@ -2229,7 +2268,7 @@ void QRhiVulkan::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::ComputePass);
if (cbD->useSecondaryCb) {
- df->vkCmdDispatch(cbD->secondaryCbs.last(), x, y, z);
+ df->vkCmdDispatch(cbD->secondaryCbs.last(), uint32_t(x), uint32_t(y), uint32_t(z));
} else {
QVkCommandBuffer::Command cmd;
cmd.cmd = QVkCommandBuffer::Command::Dispatch;
@@ -2245,7 +2284,7 @@ VkShaderModule QRhiVulkan::createShader(const QByteArray &spirv)
VkShaderModuleCreateInfo shaderInfo;
memset(&shaderInfo, 0, sizeof(shaderInfo));
shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shaderInfo.codeSize = spirv.size();
+ shaderInfo.codeSize = size_t(spirv.size());
shaderInfo.pCode = reinterpret_cast<const quint32 *>(spirv.constData());
VkShaderModule shaderModule;
VkResult err = df->vkCreateShaderModule(dev, &shaderInfo, nullptr, &shaderModule);
@@ -2285,14 +2324,14 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
VkWriteDescriptorSet writeInfo;
memset(&writeInfo, 0, sizeof(writeInfo));
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstSet = srbD->descSets[frameSlot];
- writeInfo.dstBinding = b->binding;
+ writeInfo.dstBinding = uint32_t(b->binding);
writeInfo.descriptorCount = 1;
switch (b->type) {
@@ -2306,8 +2345,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
bd.ubuf.generation = bufD->generation;
VkDescriptorBufferInfo bufInfo;
bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[frameSlot] : bufD->buffers[0];
- bufInfo.offset = b->u.ubuf.offset;
- bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size;
+ bufInfo.offset = VkDeviceSize(b->u.ubuf.offset);
+ bufInfo.range = VkDeviceSize(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size);
// be nice and assert when we know the vulkan device would die a horrible death due to non-aligned reads
Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
bufferInfos.append(bufInfo);
@@ -2364,8 +2403,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
bd.sbuf.generation = bufD->generation;
VkDescriptorBufferInfo bufInfo;
bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[frameSlot] : bufD->buffers[0];
- bufInfo.offset = b->u.ubuf.offset;
- bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size;
+ bufInfo.offset = VkDeviceSize(b->u.ubuf.offset);
+ bufInfo.range = VkDeviceSize(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size);
bufferInfos.append(bufInfo);
writeInfo.pBufferInfo = &bufferInfos.last();
}
@@ -2379,7 +2418,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
++frameSlot;
}
- df->vkUpdateDescriptorSets(dev, writeInfos.count(), writeInfos.constData(), 0, nullptr);
+ df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.count()), writeInfos.constData(), 0, nullptr);
}
static inline bool accessIsWrite(VkAccessFlags access)
@@ -2487,10 +2526,10 @@ void QRhiVulkan::subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
memset(&barrier, 0, sizeof(barrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- barrier.subresourceRange.baseMipLevel = startLevel;
- barrier.subresourceRange.levelCount = levelCount;
- barrier.subresourceRange.baseArrayLayer = startLayer;
- barrier.subresourceRange.layerCount = layerCount;
+ barrier.subresourceRange.baseMipLevel = uint32_t(startLevel);
+ barrier.subresourceRange.levelCount = uint32_t(levelCount);
+ barrier.subresourceRange.baseArrayLayer = uint32_t(startLayer);
+ barrier.subresourceRange.layerCount = uint32_t(layerCount);
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcAccessMask = srcAccess;
@@ -2511,7 +2550,7 @@ VkDeviceSize QRhiVulkan::subresUploadByteSize(const QRhiTextureSubresourceUpload
const qsizetype imageSizeBytes = subresDesc.image().isNull() ?
subresDesc.data().size() : subresDesc.image().sizeInBytes();
if (imageSizeBytes > 0)
- size += aligned(imageSizeBytes, texbufAlign);
+ size += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
return size;
}
@@ -2528,8 +2567,8 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
memset(&copyInfo, 0, sizeof(copyInfo));
copyInfo.bufferOffset = *curOfs;
copyInfo.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- copyInfo.imageSubresource.mipLevel = level;
- copyInfo.imageSubresource.baseArrayLayer = layer;
+ copyInfo.imageSubresource.mipLevel = uint32_t(level);
+ copyInfo.imageSubresource.baseArrayLayer = uint32_t(layer);
copyInfo.imageSubresource.layerCount = 1;
copyInfo.imageExtent.depth = 1;
@@ -2544,7 +2583,7 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
// be taken into account for bufferRowLength.
int bpc = qMax(1, image.depth() / 8);
// this is in pixels, not bytes, to make it more complicated...
- copyInfo.bufferRowLength = image.bytesPerLine() / bpc;
+ copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
const int sx = subresDesc.sourceTopLeft().x();
const int sy = subresDesc.sourceTopLeft().y();
@@ -2554,7 +2593,7 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
// The staging buffer will get the full image
// regardless, just adjust the vk
// buffer-to-image copy start offset.
- copyInfo.bufferOffset += sy * image.bytesPerLine() + sx * 4;
+ copyInfo.bufferOffset += VkDeviceSize(sy * image.bytesPerLine() + sx * 4);
// bufferRowLength remains set to the original image's width
} else {
image = image.copy(sx, sy, size.width(), size.height());
@@ -2563,13 +2602,13 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
// space reserved for this mip will be unused.
copySizeBytes = image.sizeInBytes();
bpc = qMax(1, image.depth() / 8);
- copyInfo.bufferRowLength = image.bytesPerLine() / bpc;
+ copyInfo.bufferRowLength = uint32_t(image.bytesPerLine() / bpc);
}
}
copyInfo.imageOffset.x = dp.x();
copyInfo.imageOffset.y = dp.y();
- copyInfo.imageExtent.width = size.width();
- copyInfo.imageExtent.height = size.height();
+ copyInfo.imageExtent.width = uint32_t(size.width());
+ copyInfo.imageExtent.height = uint32_t(size.height());
copyInfos->append(copyInfo);
} else if (!rawData.isEmpty() && isCompressedFormat(texD->m_format)) {
copySizeBytes = imageSizeBytes = rawData.size();
@@ -2588,8 +2627,8 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
copyInfo.imageOffset.y = aligned(dp.y(), blockDim.height());
// width and height must be multiples of the block width and height
// or x + width and y + height must equal the subresource width and height
- copyInfo.imageExtent.width = dp.x() + w == subresw ? w : aligned(w, blockDim.width());
- copyInfo.imageExtent.height = dp.y() + h == subresh ? h : aligned(h, blockDim.height());
+ copyInfo.imageExtent.width = uint32_t(dp.x() + w == subresw ? w : aligned(w, blockDim.width()));
+ copyInfo.imageExtent.height = uint32_t(dp.y() + h == subresh ? h : aligned(h, blockDim.height()));
copyInfos->append(copyInfo);
} else if (!rawData.isEmpty()) {
copySizeBytes = imageSizeBytes = rawData.size();
@@ -2599,15 +2638,15 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
size = subresDesc.sourceSize();
copyInfo.imageOffset.x = dp.x();
copyInfo.imageOffset.y = dp.y();
- copyInfo.imageExtent.width = size.width();
- copyInfo.imageExtent.height = size.height();
+ copyInfo.imageExtent.width = uint32_t(size.width());
+ copyInfo.imageExtent.height = uint32_t(size.height());
copyInfos->append(copyInfo);
} else {
qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
}
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, src, copySizeBytes);
- *curOfs += aligned(imageSizeBytes, texbufAlign);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs, src, size_t(copySizeBytes));
+ *curOfs += aligned(VkDeviceSize(imageSizeBytes), texbufAlign);
}
void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
@@ -2615,100 +2654,164 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
- QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
- Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
- bufD->pendingDynamicUpdates[i].append(u);
- }
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
+ if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
+ QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
+ Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
+ for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
+ bufD->pendingDynamicUpdates[i].append(u);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
+ QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
+ Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
+
+ if (!bufD->stagingBuffers[currentFrameSlot]) {
+ VkBufferCreateInfo bufferInfo;
+ memset(&bufferInfo, 0, sizeof(bufferInfo));
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ // must cover the entire buffer - this way multiple, partial updates per frame
+ // are supported even when the staging buffer is reused (Static)
+ bufferInfo.size = VkDeviceSize(bufD->m_size);
+ bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+
+ VmaAllocationCreateInfo allocInfo;
+ memset(&allocInfo, 0, sizeof(allocInfo));
+ allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
+
+ VmaAllocation allocation;
+ VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
+ &bufD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
+ if (err == VK_SUCCESS) {
+ bufD->stagingAllocations[currentFrameSlot] = allocation;
+ QRHI_PROF_F(newBufferStagingArea(bufD, currentFrameSlot, quint32(bufD->m_size)));
+ } else {
+ qWarning("Failed to create staging buffer of size %d: %d", bufD->m_size, err);
+ continue;
+ }
+ }
- for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
- QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
- Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
+ void *p = nullptr;
+ VmaAllocation a = toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]);
+ VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to map buffer: %d", err);
+ continue;
+ }
+ memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
+ vmaUnmapMemory(toVmaAllocator(allocator), a);
+ vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(u.offset), VkDeviceSize(u.data.size()));
- if (!bufD->stagingBuffers[currentFrameSlot]) {
- VkBufferCreateInfo bufferInfo;
- memset(&bufferInfo, 0, sizeof(bufferInfo));
- bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- // must cover the entire buffer - this way multiple, partial updates per frame
- // are supported even when the staging buffer is reused (Static)
- bufferInfo.size = bufD->m_size;
- bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
+ trackedBufferBarrier(cbD, bufD, 0,
+ VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
- VmaAllocationCreateInfo allocInfo;
- memset(&allocInfo, 0, sizeof(allocInfo));
- allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
+ VkBufferCopy copyInfo;
+ memset(&copyInfo, 0, sizeof(copyInfo));
+ copyInfo.srcOffset = VkDeviceSize(u.offset);
+ copyInfo.dstOffset = VkDeviceSize(u.offset);
+ copyInfo.size = VkDeviceSize(u.data.size());
- VmaAllocation allocation;
- VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
- &bufD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
- if (err == VK_SUCCESS) {
- bufD->stagingAllocations[currentFrameSlot] = allocation;
- QRHI_PROF_F(newBufferStagingArea(bufD, currentFrameSlot, bufD->m_size));
- } else {
- qWarning("Failed to create staging buffer of size %d: %d", bufD->m_size, err);
- continue;
- }
- }
+ QVkCommandBuffer::Command cmd;
+ cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
+ cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
+ cmd.args.copyBuffer.dst = bufD->buffers[0];
+ cmd.args.copyBuffer.desc = copyInfo;
+ cbD->commands.append(cmd);
- void *p = nullptr;
- VmaAllocation a = toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]);
- VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
- if (err != VK_SUCCESS) {
- qWarning("Failed to map buffer: %d", err);
- continue;
- }
- memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), u.data.size());
- vmaUnmapMemory(toVmaAllocator(allocator), a);
- vmaFlushAllocation(toVmaAllocator(allocator), a, u.offset, u.data.size());
+ // Where's the barrier for read-after-write? (assuming the common case
+ // of binding this buffer as vertex/index, or, less likely, as uniform
+ // buffer, in a renderpass later on) That is handled by the pass
+ // resource tracking: the appropriate pipeline barrier will be
+ // generated and recorded right before the renderpass, that binds this
+ // buffer in one of its commands, gets its BeginRenderPass recorded.
- trackedBufferBarrier(cbD, bufD, 0,
- VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
+ bufD->lastActiveFrameSlot = currentFrameSlot;
- VkBufferCopy copyInfo;
- memset(&copyInfo, 0, sizeof(copyInfo));
- copyInfo.srcOffset = u.offset;
- copyInfo.dstOffset = u.offset;
- copyInfo.size = u.data.size();
+ if (bufD->m_type == QRhiBuffer::Immutable) {
+ QRhiVulkan::DeferredReleaseEntry e;
+ e.type = QRhiVulkan::DeferredReleaseEntry::StagingBuffer;
+ e.lastActiveFrameSlot = currentFrameSlot;
+ e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
+ e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
+ bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
+ bufD->stagingAllocations[currentFrameSlot] = nullptr;
+ releaseQueue.append(e);
+ QRHI_PROF_F(releaseBufferStagingArea(bufD, currentFrameSlot));
+ }
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
+ QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
+ if (bufD->m_type == QRhiBuffer::Dynamic) {
+ executeBufferHostWritesForCurrentFrame(bufD);
+ void *p = nullptr;
+ VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]);
+ VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
+ if (err == VK_SUCCESS) {
+ u.result->data.resize(u.readSize);
+ memcpy(u.result->data.data(), reinterpret_cast<char *>(p) + u.offset, size_t(u.readSize));
+ vmaUnmapMemory(toVmaAllocator(allocator), a);
+ }
+ if (u.result->completed)
+ u.result->completed();
+ } else {
+ // Non-Dynamic buffers may not be host visible, so have to
+ // create a readback buffer, enqueue a copy from
+ // bufD->buffers[0] to this buffer, and then once the command
+ // buffer completes, copy the data out of the host visible
+ // readback buffer. Quite similar to what we do for texture
+ // readbacks.
+ BufferReadback readback;
+ readback.activeFrameSlot = currentFrameSlot;
+ readback.result = u.result;
+ readback.byteSize = u.readSize;
+
+ VkBufferCreateInfo bufferInfo;
+ memset(&bufferInfo, 0, sizeof(bufferInfo));
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferInfo.size = VkDeviceSize(readback.byteSize);
+ bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+
+ VmaAllocationCreateInfo allocInfo;
+ memset(&allocInfo, 0, sizeof(allocInfo));
+ allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
+
+ VmaAllocation allocation;
+ VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
+ if (err == VK_SUCCESS) {
+ readback.stagingAlloc = allocation;
+ QRHI_PROF_F(newReadbackBuffer(qint64(readback.stagingBuf), bufD, uint(readback.byteSize)));
+ } else {
+ qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
+ continue;
+ }
- QVkCommandBuffer::Command cmd;
- cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
- cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
- cmd.args.copyBuffer.dst = bufD->buffers[0];
- cmd.args.copyBuffer.desc = copyInfo;
- cbD->commands.append(cmd);
+ trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
- // Where's the barrier for read-after-write? (assuming the common case
- // of binding this buffer as vertex/index, or, less likely, as uniform
- // buffer, in a renderpass later on) That is handled by the pass
- // resource tracking: the appropriate pipeline barrier will be
- // generated and recorded right before the renderpass, that binds this
- // buffer in one of its commands, gets its BeginRenderPass recorded.
+ VkBufferCopy copyInfo;
+ memset(&copyInfo, 0, sizeof(copyInfo));
+ copyInfo.srcOffset = VkDeviceSize(u.offset);
+ copyInfo.size = VkDeviceSize(u.readSize);
- bufD->lastActiveFrameSlot = currentFrameSlot;
+ QVkCommandBuffer::Command cmd;
+ cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
+ cmd.args.copyBuffer.src = bufD->buffers[0];
+ cmd.args.copyBuffer.dst = readback.stagingBuf;
+ cmd.args.copyBuffer.desc = copyInfo;
+ cbD->commands.append(cmd);
- if (bufD->m_type == QRhiBuffer::Immutable) {
- QRhiVulkan::DeferredReleaseEntry e;
- e.type = QRhiVulkan::DeferredReleaseEntry::StagingBuffer;
- e.lastActiveFrameSlot = currentFrameSlot;
- e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
- e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
- bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
- bufD->stagingAllocations[currentFrameSlot] = nullptr;
- releaseQueue.append(e);
- QRHI_PROF_F(releaseBufferStagingArea(bufD, currentFrameSlot));
+ bufD->lastActiveFrameSlot = currentFrameSlot;
+
+ activeBufferReadbacks.append(readback);
+ }
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
- QVkTexture *utexD = QRHI_RES(QVkTexture, u.upload.tex);
+ QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst);
// batch into a single staging buffer and a single CopyBufferToImage with multiple copyInfos
VkDeviceSize stagingSize = 0;
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
+ for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
stagingSize += subresUploadByteSize(subresDesc);
}
}
@@ -2732,7 +2835,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
continue;
}
utexD->stagingAllocations[currentFrameSlot] = allocation;
- QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, stagingSize));
+ QRHI_PROF_F(newTextureStagingArea(utexD, currentFrameSlot, quint32(stagingSize)));
BufferImageCopyList copyInfos;
size_t curOfs = 0;
@@ -2746,7 +2849,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
- const QVector<QRhiTextureSubresourceUploadDescription> &srd(u.upload.subresDesc[layer][level]);
+ const QVector<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
if (srd.isEmpty())
continue;
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(srd)) {
@@ -2787,36 +2890,37 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
utexD->lastActiveFrameSlot = currentFrameSlot;
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
- Q_ASSERT(u.copy.src && u.copy.dst);
- if (u.copy.src == u.copy.dst) {
+ Q_ASSERT(u.src && u.dst);
+ if (u.src == u.dst) {
qWarning("Texture copy with matching source and destination is not supported");
continue;
}
- QVkTexture *srcD = QRHI_RES(QVkTexture, u.copy.src);
- QVkTexture *dstD = QRHI_RES(QVkTexture, u.copy.dst);
+ QVkTexture *srcD = QRHI_RES(QVkTexture, u.src);
+ QVkTexture *dstD = QRHI_RES(QVkTexture, u.dst);
VkImageCopy region;
memset(&region, 0, sizeof(region));
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- region.srcSubresource.mipLevel = u.copy.desc.sourceLevel();
- region.srcSubresource.baseArrayLayer = u.copy.desc.sourceLayer();
+ region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
+ region.srcSubresource.baseArrayLayer = uint32_t(u.desc.sourceLayer());
region.srcSubresource.layerCount = 1;
- region.srcOffset.x = u.copy.desc.sourceTopLeft().x();
- region.srcOffset.y = u.copy.desc.sourceTopLeft().y();
+ region.srcOffset.x = u.desc.sourceTopLeft().x();
+ region.srcOffset.y = u.desc.sourceTopLeft().y();
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- region.dstSubresource.mipLevel = u.copy.desc.destinationLevel();
- region.dstSubresource.baseArrayLayer = u.copy.desc.destinationLayer();
+ region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
+ region.dstSubresource.baseArrayLayer = uint32_t(u.desc.destinationLayer());
region.dstSubresource.layerCount = 1;
- region.dstOffset.x = u.copy.desc.destinationTopLeft().x();
- region.dstOffset.y = u.copy.desc.destinationTopLeft().y();
+ region.dstOffset.x = u.desc.destinationTopLeft().x();
+ region.dstOffset.y = u.desc.destinationTopLeft().y();
- const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
- region.extent.width = size.width();
- region.extent.height = size.height();
+ const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
+ const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
+ region.extent.width = uint32_t(copySize.width());
+ region.extent.height = uint32_t(copySize.height());
region.extent.depth = 1;
trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
@@ -2835,21 +2939,20 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
- ActiveReadback aRb;
- aRb.activeFrameSlot = currentFrameSlot;
- aRb.desc = u.read.rb;
- aRb.result = u.read.result;
+ TextureReadback readback;
+ readback.activeFrameSlot = currentFrameSlot;
+ readback.desc = u.rb;
+ readback.result = u.result;
- QVkTexture *texD = QRHI_RES(QVkTexture, u.read.rb.texture());
+ QVkTexture *texD = QRHI_RES(QVkTexture, u.rb.texture());
QVkSwapChain *swapChainD = nullptr;
if (texD) {
if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
qWarning("Multisample texture cannot be read back");
continue;
}
- aRb.pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize)
- : texD->m_pixelSize;
- aRb.format = texD->m_format;
+ readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
+ readback.format = texD->m_format;
texD->lastActiveFrameSlot = currentFrameSlot;
} else {
Q_ASSERT(currentSwapChain);
@@ -2858,21 +2961,21 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
qWarning("Swapchain does not support readback");
continue;
}
- aRb.pixelSize = swapChainD->pixelSize;
- aRb.format = colorTextureFormatFromVkFormat(swapChainD->colorFormat, nullptr);
- if (aRb.format == QRhiTexture::UnknownFormat)
+ readback.pixelSize = swapChainD->pixelSize;
+ readback.format = colorTextureFormatFromVkFormat(swapChainD->colorFormat, nullptr);
+ if (readback.format == QRhiTexture::UnknownFormat)
continue;
// Multisample swapchains need nothing special since resolving
// happens when ending a renderpass.
}
- textureFormatInfo(aRb.format, aRb.pixelSize, nullptr, &aRb.bufSize);
+ textureFormatInfo(readback.format, readback.pixelSize, nullptr, &readback.byteSize);
- // Create a host visible buffer.
+ // Create a host visible readback buffer.
VkBufferCreateInfo bufferInfo;
memset(&bufferInfo, 0, sizeof(bufferInfo));
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- bufferInfo.size = aRb.bufSize;
+ bufferInfo.size = readback.byteSize;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VmaAllocationCreateInfo allocInfo;
@@ -2880,14 +2983,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
VmaAllocation allocation;
- VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &aRb.buf, &allocation, nullptr);
+ VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
if (err == VK_SUCCESS) {
- aRb.bufAlloc = allocation;
- QRHI_PROF_F(newReadbackBuffer(quint64(aRb.buf),
+ readback.stagingAlloc = allocation;
+ QRHI_PROF_F(newReadbackBuffer(qint64(readback.stagingBuf),
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
- aRb.bufSize));
+ readback.byteSize));
} else {
- qWarning("Failed to create readback buffer of size %u: %d", aRb.bufSize, err);
+ qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
continue;
}
@@ -2896,11 +2999,11 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
memset(&copyDesc, 0, sizeof(copyDesc));
copyDesc.bufferOffset = 0;
copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- copyDesc.imageSubresource.mipLevel = u.read.rb.level();
- copyDesc.imageSubresource.baseArrayLayer = u.read.rb.layer();
+ copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
+ copyDesc.imageSubresource.baseArrayLayer = uint32_t(u.rb.layer());
copyDesc.imageSubresource.layerCount = 1;
- copyDesc.imageExtent.width = aRb.pixelSize.width();
- copyDesc.imageExtent.height = aRb.pixelSize.height();
+ copyDesc.imageExtent.width = uint32_t(readback.pixelSize.width());
+ copyDesc.imageExtent.height = uint32_t(readback.pixelSize.height());
copyDesc.imageExtent.depth = 1;
if (texD) {
@@ -2910,7 +3013,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
cmd.args.copyImageToBuffer.src = texD->image;
cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
- cmd.args.copyImageToBuffer.dst = aRb.buf;
+ cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
cmd.args.copyImageToBuffer.desc = copyDesc;
cbD->commands.append(cmd);
} else {
@@ -2935,14 +3038,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
cmd.args.copyImageToBuffer.src = image;
cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- cmd.args.copyImageToBuffer.dst = aRb.buf;
+ cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
cmd.args.copyImageToBuffer.desc = copyDesc;
cbD->commands.append(cmd);
}
- activeReadbacks.append(aRb);
- } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
- QVkTexture *utexD = QRHI_RES(QVkTexture, u.mipgen.tex);
+ activeTextureReadbacks.append(readback);
+ } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
+ QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst);
Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
int w = utexD->m_pixelSize.width();
int h = utexD->m_pixelSize.height();
@@ -2953,20 +3056,20 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
if (!origStage)
origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
- for (uint level = 1; level < utexD->mipLevelCount; ++level) {
+ for (int level = 1; level < int(utexD->mipLevelCount); ++level) {
if (level == 1) {
subresourceBarrier(cbD, utexD->image,
origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
origAccess, VK_ACCESS_TRANSFER_READ_BIT,
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
- u.mipgen.layer, 1,
+ u.layer, 1,
level - 1, 1);
} else {
subresourceBarrier(cbD, utexD->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
- u.mipgen.layer, 1,
+ u.layer, 1,
level - 1, 1);
}
@@ -2974,15 +3077,15 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
- u.mipgen.layer, 1,
+ u.layer, 1,
level, 1);
VkImageBlit region;
memset(&region, 0, sizeof(region));
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- region.srcSubresource.mipLevel = level - 1;
- region.srcSubresource.baseArrayLayer = u.mipgen.layer;
+ region.srcSubresource.mipLevel = uint32_t(level) - 1;
+ region.srcSubresource.baseArrayLayer = uint32_t(u.layer);
region.srcSubresource.layerCount = 1;
region.srcOffsets[1].x = qMax(1, w);
@@ -2990,8 +3093,8 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
region.srcOffsets[1].z = 1;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- region.dstSubresource.mipLevel = level;
- region.dstSubresource.baseArrayLayer = u.mipgen.layer;
+ region.dstSubresource.mipLevel = uint32_t(level);
+ region.dstSubresource.baseArrayLayer = uint32_t(u.layer);
region.dstSubresource.layerCount = 1;
region.dstOffsets[1].x = qMax(1, w >> 1);
@@ -3017,14 +3120,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
VK_ACCESS_TRANSFER_READ_BIT, origAccess,
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
- u.mipgen.layer, 1,
- 0, utexD->mipLevelCount - 1);
+ u.layer, 1,
+ 0, int(utexD->mipLevelCount) - 1);
subresourceBarrier(cbD, utexD->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
- u.mipgen.layer, 1,
- utexD->mipLevelCount - 1, 1);
+ u.layer, 1,
+ int(utexD->mipLevelCount) - 1, 1);
}
utexD->lastActiveFrameSlot = currentFrameSlot;
@@ -3036,8 +3139,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
{
- QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->pendingDynamicUpdates[currentFrameSlot]);
- if (updates.isEmpty())
+ if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty())
return;
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
@@ -3053,9 +3155,9 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
}
int changeBegin = -1;
int changeEnd = -1;
- for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : updates) {
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) {
Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf));
- memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), u.data.size());
+ memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
@@ -3063,9 +3165,9 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
}
vmaUnmapMemory(toVmaAllocator(allocator), a);
if (changeBegin >= 0)
- vmaFlushAllocation(toVmaAllocator(allocator), a, changeBegin, changeEnd - changeBegin);
+ vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin));
- updates.clear();
+ bufD->pendingDynamicUpdates[currentFrameSlot].clear();
}
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
@@ -3159,29 +3261,53 @@ void QRhiVulkan::finishActiveReadbacks(bool forced)
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
- for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
- const QRhiVulkan::ActiveReadback &aRb(activeReadbacks[i]);
- if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
- aRb.result->format = aRb.format;
- aRb.result->pixelSize = aRb.pixelSize;
- aRb.result->data.resize(aRb.bufSize);
+ for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
+ const QRhiVulkan::TextureReadback &readback(activeTextureReadbacks[i]);
+ if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
+ readback.result->format = readback.format;
+ readback.result->pixelSize = readback.pixelSize;
+ VmaAllocation a = toVmaAllocation(readback.stagingAlloc);
void *p = nullptr;
- VmaAllocation a = toVmaAllocation(aRb.bufAlloc);
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
- if (err != VK_SUCCESS) {
- qWarning("Failed to map readback buffer: %d", err);
- continue;
+ if (err == VK_SUCCESS && p) {
+ readback.result->data.resize(int(readback.byteSize));
+ memcpy(readback.result->data.data(), p, readback.byteSize);
+ vmaUnmapMemory(toVmaAllocator(allocator), a);
+ } else {
+ qWarning("Failed to map texture readback buffer of size %u: %d", readback.byteSize, err);
}
- memcpy(aRb.result->data.data(), p, aRb.bufSize);
- vmaUnmapMemory(toVmaAllocator(allocator), a);
- vmaDestroyBuffer(toVmaAllocator(allocator), aRb.buf, a);
- QRHI_PROF_F(releaseReadbackBuffer(quint64(aRb.buf)));
+ vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, a);
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(readback.stagingBuf)));
+
+ if (readback.result->completed)
+ completedCallbacks.append(readback.result->completed);
+
+ activeTextureReadbacks.removeAt(i);
+ }
+ }
+
+ for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
+ const QRhiVulkan::BufferReadback &readback(activeBufferReadbacks[i]);
+ if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
+ VmaAllocation a = toVmaAllocation(readback.stagingAlloc);
+ void *p = nullptr;
+ VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
+ if (err == VK_SUCCESS && p) {
+ readback.result->data.resize(readback.byteSize);
+ memcpy(readback.result->data.data(), p, size_t(readback.byteSize));
+ vmaUnmapMemory(toVmaAllocator(allocator), a);
+ } else {
+ qWarning("Failed to map buffer readback buffer of size %d: %d", readback.byteSize, err);
+ }
- if (aRb.result->completed)
- completedCallbacks.append(aRb.result->completed);
+ vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, a);
+ QRHI_PROF_F(releaseReadbackBuffer(qint64(readback.stagingBuf)));
- activeReadbacks.removeAt(i);
+ if (readback.result->completed)
+ completedCallbacks.append(readback.result->completed);
+
+ activeBufferReadbacks.removeAt(i);
}
}
@@ -3211,12 +3337,12 @@ QVector<int> QRhiVulkan::supportedSampleCounts() const
VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
QVector<int> result;
- for (size_t i = 0; i < sizeof(qvk_sampleCounts) / sizeof(qvk_sampleCounts[0]); ++i) {
- if ((color & qvk_sampleCounts[i].mask)
- && (depth & qvk_sampleCounts[i].mask)
- && (stencil & qvk_sampleCounts[i].mask))
+ for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ if ((color & qvk_sampleCount.mask)
+ && (depth & qvk_sampleCount.mask)
+ && (stencil & qvk_sampleCount.mask))
{
- result.append(qvk_sampleCounts[i].count);
+ result.append(qvk_sampleCount.count);
}
}
@@ -3233,9 +3359,9 @@ VkSampleCountFlagBits QRhiVulkan::effectiveSampleCount(int sampleCount)
return VK_SAMPLE_COUNT_1_BIT;
}
- for (size_t i = 0; i < sizeof(qvk_sampleCounts) / sizeof(qvk_sampleCounts[0]); ++i) {
- if (qvk_sampleCounts[i].count == sampleCount)
- return qvk_sampleCounts[i].mask;
+ for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ if (qvk_sampleCount.count == sampleCount)
+ return qvk_sampleCount.mask;
}
Q_UNREACHABLE();
@@ -3266,7 +3392,7 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
case QVkCommandBuffer::Command::CopyBufferToImage:
df->vkCmdCopyBufferToImage(cbD->cb, cmd.args.copyBufferToImage.src, cmd.args.copyBufferToImage.dst,
cmd.args.copyBufferToImage.dstLayout,
- cmd.args.copyBufferToImage.count,
+ uint32_t(cmd.args.copyBufferToImage.count),
cbD->pools.bufferImageCopy.constData() + cmd.args.copyBufferToImage.bufferImageCopyIndex);
break;
case QVkCommandBuffer::Command::CopyImage:
@@ -3315,13 +3441,13 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
df->vkCmdBindDescriptorSets(cbD->cb, cmd.args.bindDescriptorSet.bindPoint,
cmd.args.bindDescriptorSet.pipelineLayout,
0, 1, &cmd.args.bindDescriptorSet.descSet,
- cmd.args.bindDescriptorSet.dynamicOffsetCount,
+ uint32_t(cmd.args.bindDescriptorSet.dynamicOffsetCount),
offsets);
}
break;
case QVkCommandBuffer::Command::BindVertexBuffer:
- df->vkCmdBindVertexBuffers(cbD->cb, cmd.args.bindVertexBuffer.startBinding,
- cmd.args.bindVertexBuffer.count,
+ df->vkCmdBindVertexBuffers(cbD->cb, uint32_t(cmd.args.bindVertexBuffer.startBinding),
+ uint32_t(cmd.args.bindVertexBuffer.count),
cbD->pools.vertexBuffer.constData() + cmd.args.bindVertexBuffer.vertexBufferIndex,
cbD->pools.vertexBufferOffset.constData() + cmd.args.bindVertexBuffer.vertexBufferOffsetIndex);
break;
@@ -3367,7 +3493,7 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
recordTransitionPassResources(cbD, cbD->passResTrackers[cmd.args.transitionResources.trackerIndex]);
break;
case QVkCommandBuffer::Command::Dispatch:
- df->vkCmdDispatch(cbD->cb, cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
+ df->vkCmdDispatch(cbD->cb, uint32_t(cmd.args.dispatch.x), uint32_t(cmd.args.dispatch.y), uint32_t(cmd.args.dispatch.z));
break;
case QVkCommandBuffer::Command::ExecuteSecondary:
df->vkCmdExecuteCommands(cbD->cb, 1, &cmd.args.executeSecondary.cb);
@@ -3421,8 +3547,8 @@ static inline VkPipelineStageFlags toVkPipelineStage(QRhiPassResourceTracker::Bu
static inline QVkBuffer::UsageState toVkBufferUsageState(QRhiPassResourceTracker::UsageState usage)
{
QVkBuffer::UsageState u;
- u.access = usage.access;
- u.stage = usage.stage;
+ u.access = VkAccessFlags(usage.access);
+ u.stage = VkPipelineStageFlags(usage.stage);
return u;
}
@@ -3494,8 +3620,8 @@ static inline QVkTexture::UsageState toVkTextureUsageState(QRhiPassResourceTrack
{
QVkTexture::UsageState u;
u.layout = VkImageLayout(usage.layout);
- u.access = usage.access;
- u.stage = usage.stage;
+ u.access = VkAccessFlags(usage.access);
+ u.stage = VkPipelineStageFlags(usage.stage);
return u;
}
@@ -3528,12 +3654,11 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
if (tracker.isEmpty())
return;
- const QVector<QRhiPassResourceTracker::Buffer> *buffers = tracker.buffers();
- for (const QRhiPassResourceTracker::Buffer &b : *buffers) {
- QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.buf);
- VkAccessFlags access = toVkAccess(b.access);
- VkPipelineStageFlags stage = toVkPipelineStage(b.stage);
- QVkBuffer::UsageState s = toVkBufferUsageState(b.stateAtPassBegin);
+ for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
+ QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
+ VkAccessFlags access = toVkAccess(it->access);
+ VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
+ QVkBuffer::UsageState s = toVkBufferUsageState(it->stateAtPassBegin);
if (!s.stage)
continue;
if (s.access == access && s.stage == stage) {
@@ -3547,7 +3672,7 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
bufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufMemBarrier.srcAccessMask = s.access;
bufMemBarrier.dstAccessMask = access;
- bufMemBarrier.buffer = bufD->buffers[b.slot];
+ bufMemBarrier.buffer = bufD->buffers[it->slot];
bufMemBarrier.size = VK_WHOLE_SIZE;
df->vkCmdPipelineBarrier(cbD->cb, s.stage, stage, 0,
0, nullptr,
@@ -3555,13 +3680,12 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
0, nullptr);
}
- const QVector<QRhiPassResourceTracker::Texture> *textures = tracker.textures();
- for (const QRhiPassResourceTracker::Texture &t : *textures) {
- QVkTexture *texD = QRHI_RES(QVkTexture, t.tex);
- VkImageLayout layout = toVkLayout(t.access);
- VkAccessFlags access = toVkAccess(t.access);
- VkPipelineStageFlags stage = toVkPipelineStage(t.stage);
- QVkTexture::UsageState s = toVkTextureUsageState(t.stateAtPassBegin);
+ for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
+ VkImageLayout layout = toVkLayout(it->access);
+ VkAccessFlags access = toVkAccess(it->access);
+ VkPipelineStageFlags stage = toVkPipelineStage(it->stage);
+ QVkTexture::UsageState s = toVkTextureUsageState(it->stateAtPassBegin);
if (s.access == access && s.stage == stage && s.layout == layout) {
if (!accessIsWrite(access))
continue;
@@ -3603,7 +3727,7 @@ QRhiBuffer *QRhiVulkan::createBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFla
int QRhiVulkan::ubufAlignment() const
{
- return ubufAlign; // typically 256 (bytes)
+ return int(ubufAlign); // typically 256 (bytes)
}
bool QRhiVulkan::isYUpInFramebuffer() const
@@ -3699,6 +3823,12 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::BaseInstance:
return true;
+ case QRhi::TriangleFanTopology:
+ return true;
+ case QRhi::ReadBackNonUniformBuffer:
+ return true;
+ case QRhi::ReadBackNonBaseMipLevel:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -3711,9 +3841,9 @@ int QRhiVulkan::resourceLimit(QRhi::ResourceLimit limit) const
case QRhi::TextureSizeMin:
return 1;
case QRhi::TextureSizeMax:
- return physDevProperties.limits.maxImageDimension2D;
+ return int(physDevProperties.limits.maxImageDimension2D);
case QRhi::MaxColorAttachments:
- return physDevProperties.limits.maxColorAttachments;
+ return int(physDevProperties.limits.maxColorAttachments);
case QRhi::FramesInFlight:
return QVK_FRAMES_IN_FLIGHT;
default:
@@ -3736,14 +3866,25 @@ void QRhiVulkan::sendVMemStatsToProfiler()
VmaStats stats;
vmaCalculateStats(toVmaAllocator(allocator), &stats);
QRHI_PROF_F(vmemStat(stats.total.blockCount, stats.total.allocationCount,
- stats.total.usedBytes, stats.total.unusedBytes));
+ quint32(stats.total.usedBytes), quint32(stats.total.unusedBytes)));
+}
+
+bool QRhiVulkan::makeThreadLocalNativeContextCurrent()
+{
+ // not applicable
+ return false;
}
-void QRhiVulkan::makeThreadLocalNativeContextCurrent()
+void QRhiVulkan::releaseCachedResources()
{
// nothing to do here
}
+bool QRhiVulkan::isDeviceLost() const
+{
+ return deviceLost;
+}
+
QRhiRenderBuffer *QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
@@ -3831,7 +3972,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
bool hasDynamicOffsetInSrb = false;
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
+ const QRhiShaderResourceBinding::Data *b = binding.data();
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
@@ -3850,7 +3991,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// Do host writes and mark referenced shader resources as in-use.
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
+ const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
QRhiPassResourceTracker &passResTracker(cbD->passResTrackers[cbD->currentPassResTrackerIndex]);
switch (b->type) {
@@ -3983,7 +4124,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
// and neither srb nor dynamicOffsets has any such ordering
// requirement.
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
+ const QRhiShaderResourceBinding::Data *b = binding.data();
if (b->type == QRhiShaderResourceBinding::UniformBuffer && b->u.ubuf.hasDynamicOffset) {
uint32_t offset = 0;
for (int i = 0; i < dynamicOffsetCount; ++i) {
@@ -4003,7 +4144,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
gfxPsD ? VK_PIPELINE_BIND_POINT_GRAPHICS : VK_PIPELINE_BIND_POINT_COMPUTE,
gfxPsD ? gfxPsD->layout : compPsD->layout,
0, 1, &srbD->descSets[descSetIdx],
- dynOfs.count(),
+ uint32_t(dynOfs.count()),
dynOfs.count() ? dynOfs.constData() : nullptr);
} else {
QVkCommandBuffer::Command cmd;
@@ -4073,8 +4214,8 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb,
}
if (cbD->useSecondaryCb) {
- df->vkCmdBindVertexBuffers(cbD->secondaryCbs.last(), startBinding,
- bufs.count(), bufs.constData(), ofs.constData());
+ df->vkCmdBindVertexBuffers(cbD->secondaryCbs.last(), uint32_t(startBinding),
+ uint32_t(bufs.count()), bufs.constData(), ofs.constData());
} else {
QVkCommandBuffer::Command cmd;
cmd.cmd = QVkCommandBuffer::Command::BindVertexBuffer;
@@ -4155,10 +4296,10 @@ void QRhiVulkan::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport
if (!QRHI_RES(QVkGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
VkRect2D *s = &cmd.args.setScissor.scissor;
- s->offset.x = x;
- s->offset.y = y;
- s->extent.width = w;
- s->extent.height = h;
+ s->offset.x = int32_t(x);
+ s->offset.y = int32_t(y);
+ s->extent.width = uint32_t(w);
+ s->extent.height = uint32_t(h);
if (cbD->useSecondaryCb) {
df->vkCmdSetScissor(cbD->secondaryCbs.last(), 0, 1, s);
} else {
@@ -4184,8 +4325,8 @@ void QRhiVulkan::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
VkRect2D *s = &cmd.args.setScissor.scissor;
s->offset.x = x;
s->offset.y = y;
- s->extent.width = w;
- s->extent.height = h;
+ s->extent.width = uint32_t(w);
+ s->extent.height = uint32_t(h);
if (cbD->useSecondaryCb) {
df->vkCmdSetScissor(cbD->secondaryCbs.last(), 0, 1, s);
@@ -4206,10 +4347,10 @@ void QRhiVulkan::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
} else {
QVkCommandBuffer::Command cmd;
cmd.cmd = QVkCommandBuffer::Command::SetBlendConstants;
- cmd.args.setBlendConstants.c[0] = c.redF();
- cmd.args.setBlendConstants.c[1] = c.greenF();
- cmd.args.setBlendConstants.c[2] = c.blueF();
- cmd.args.setBlendConstants.c[3] = c.alphaF();
+ cmd.args.setBlendConstants.c[0] = float(c.redF());
+ cmd.args.setBlendConstants.c[1] = float(c.greenF());
+ cmd.args.setBlendConstants.c[2] = float(c.blueF());
+ cmd.args.setBlendConstants.c[3] = float(c.alphaF());
cbD->commands.append(cmd);
}
}
@@ -4533,6 +4674,8 @@ static inline VkPrimitiveTopology toVkTopology(QRhiGraphicsPipeline::Topology t)
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case QRhiGraphicsPipeline::TriangleStrip:
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ case QRhiGraphicsPipeline::TriangleFan:
+ return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
case QRhiGraphicsPipeline::Lines:
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
case QRhiGraphicsPipeline::LineStrip:
@@ -4711,7 +4854,7 @@ static inline void fillVkStencilOpState(VkStencilOpState *dst, const QRhiGraphic
dst->compareOp = toVkCompareOp(src.compareOp);
}
-static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindingPrivate *b)
+static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBinding::Data *b)
{
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
@@ -4838,7 +4981,7 @@ bool QVkBuffer::build()
VkBufferCreateInfo bufferInfo;
memset(&bufferInfo, 0, sizeof(bufferInfo));
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- bufferInfo.size = nonZeroSize;
+ bufferInfo.size = uint32_t(nonZeroSize);
bufferInfo.usage = toVkBufferUsage(m_usage);
VmaAllocationCreateInfo allocInfo;
@@ -4855,7 +4998,7 @@ bool QVkBuffer::build()
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
} else {
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
- bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
}
QRHI_RES_RHI(QRhiVulkan);
@@ -4869,11 +5012,7 @@ bool QVkBuffer::build()
err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation, nullptr);
if (err != VK_SUCCESS)
break;
-
allocations[i] = allocation;
- if (m_type == Dynamic)
- pendingDynamicUpdates[i].reserve(16);
-
rhiD->setObjectName(uint64_t(buffers[i]), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, m_objectName,
m_type == Dynamic ? i : -1);
}
@@ -4885,7 +5024,7 @@ bool QVkBuffer::build()
}
QRHI_PROF;
- QRHI_PROF_F(newBuffer(this, nonZeroSize, m_type != Dynamic ? 1 : QVK_FRAMES_IN_FLIGHT, 0));
+ QRHI_PROF_F(newBuffer(this, uint(nonZeroSize), m_type != Dynamic ? 1 : QVK_FRAMES_IN_FLIGHT, 0));
lastActiveFrameSlot = -1;
generation += 1;
@@ -5076,7 +5215,7 @@ bool QVkTexture::prepareBuild(QSize *adjustedSize)
const bool isCube = m_flags.testFlag(CubeMap);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
- mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
+ mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
const int maxLevels = QRhi::MAX_LEVELS;
if (mipLevelCount > maxLevels) {
qWarning("Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
@@ -5155,8 +5294,8 @@ bool QVkTexture::build()
imageInfo.flags = isCube ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = vkformat;
- imageInfo.extent.width = size.width();
- imageInfo.extent.height = size.height();
+ imageInfo.extent.width = uint32_t(size.width());
+ imageInfo.extent.height = uint32_t(size.height());
imageInfo.extent.depth = 1;
imageInfo.mipLevels = mipLevelCount;
imageInfo.arrayLayers = isCube ? 6 : 1;
@@ -5197,7 +5336,7 @@ bool QVkTexture::build()
rhiD->setObjectName(uint64_t(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, m_objectName);
QRHI_PROF;
- QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, samples));
+ QRHI_PROF_F(newTexture(this, true, int(mipLevelCount), isCube ? 6 : 1, samples));
owns = true;
rhiD->registerResource(this);
@@ -5219,7 +5358,7 @@ bool QVkTexture::buildFrom(const QRhiNativeHandles *src)
return false;
QRHI_PROF;
- QRHI_PROF_F(newTexture(this, false, mipLevelCount, m_flags.testFlag(CubeMap) ? 6 : 1, samples));
+ QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, samples));
usageState.layout = h->layout;
@@ -5255,7 +5394,7 @@ VkImageView QVkTexture::imageViewForLevel(int level)
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
viewInfo.subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = level;
+ viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = isCube ? 6 : 1;
@@ -5450,7 +5589,8 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip
QRHI_RES_RHI(QRhiVulkan);
QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi);
if (!rhiD->createOffscreenRenderPass(&rp->rp,
- m_desc.colorAttachments(),
+ m_desc.cbeginColorAttachments(),
+ m_desc.cendColorAttachments(),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
m_desc.depthStencilBuffer(),
@@ -5470,18 +5610,20 @@ bool QVkTextureRenderTarget::build()
if (d.fb)
release();
- const QVector<QRhiColorAttachment> colorAttachments = m_desc.colorAttachments();
- Q_ASSERT(!colorAttachments.isEmpty() || m_desc.depthTexture());
+ const bool hasColorAttachments = m_desc.cbeginColorAttachments() != m_desc.cendColorAttachments();
+ Q_ASSERT(hasColorAttachments || m_desc.depthTexture());
Q_ASSERT(!m_desc.depthStencilBuffer() || !m_desc.depthTexture());
const bool hasDepthStencil = m_desc.depthStencilBuffer() || m_desc.depthTexture();
QRHI_RES_RHI(QRhiVulkan);
QVarLengthArray<VkImageView, 8> views;
- d.colorAttCount = colorAttachments.count();
- for (int i = 0; i < d.colorAttCount; ++i) {
- QVkTexture *texD = QRHI_RES(QVkTexture, colorAttachments[i].texture());
- QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, colorAttachments[i].renderBuffer());
+ d.colorAttCount = 0;
+ int attIndex = 0;
+ for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
+ d.colorAttCount += 1;
+ QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
+ QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
if (texD) {
Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
@@ -5496,24 +5638,24 @@ bool QVkTextureRenderTarget::build()
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = colorAttachments[i].level();
+ viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = colorAttachments[i].layer();
+ viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
viewInfo.subresourceRange.layerCount = 1;
- VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &rtv[i]);
+ VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &rtv[attIndex]);
if (err != VK_SUCCESS) {
qWarning("Failed to create render target image view: %d", err);
return false;
}
- views.append(rtv[i]);
- if (i == 0) {
+ views.append(rtv[attIndex]);
+ if (attIndex == 0) {
d.pixelSize = texD->pixelSize();
d.sampleCount = texD->samples;
}
} else if (rbD) {
Q_ASSERT(rbD->backingTexture);
views.append(rbD->backingTexture->imageView);
- if (i == 0) {
+ if (attIndex == 0) {
d.pixelSize = rbD->pixelSize();
d.sampleCount = rbD->samples;
}
@@ -5543,9 +5685,10 @@ bool QVkTextureRenderTarget::build()
}
d.resolveAttCount = 0;
- for (int i = 0; i < d.colorAttCount; ++i) {
- if (colorAttachments[i].resolveTexture()) {
- QVkTexture *resTexD = QRHI_RES(QVkTexture, colorAttachments[i].resolveTexture());
+ attIndex = 0;
+ for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
+ if (it->resolveTexture()) {
+ QVkTexture *resTexD = QRHI_RES(QVkTexture, it->resolveTexture());
Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
d.resolveAttCount += 1;
@@ -5560,16 +5703,16 @@ bool QVkTextureRenderTarget::build()
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.subresourceRange.baseMipLevel = colorAttachments[i].resolveLevel();
+ viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = colorAttachments[i].resolveLayer();
+ viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
viewInfo.subresourceRange.layerCount = 1;
- VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resrtv[i]);
+ VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resrtv[attIndex]);
if (err != VK_SUCCESS) {
qWarning("Failed to create render target resolve image view: %d", err);
return false;
}
- views.append(resrtv[i]);
+ views.append(resrtv[attIndex]);
}
}
@@ -5583,10 +5726,10 @@ bool QVkTextureRenderTarget::build()
memset(&fbInfo, 0, sizeof(fbInfo));
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = d.rp->rp;
- fbInfo.attachmentCount = d.colorAttCount + d.dsAttCount + d.resolveAttCount;
+ fbInfo.attachmentCount = uint32_t(d.colorAttCount + d.dsAttCount + d.resolveAttCount);
fbInfo.pAttachments = views.constData();
- fbInfo.width = d.pixelSize.width();
- fbInfo.height = d.pixelSize.height();
+ fbInfo.width = uint32_t(d.pixelSize.width());
+ fbInfo.height = uint32_t(d.pixelSize.height());
fbInfo.layers = 1;
VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo, nullptr, &d.fb);
@@ -5658,19 +5801,20 @@ bool QVkShaderResourceBindings::build()
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
descSets[i] = VK_NULL_HANDLE;
- sortedBindings = m_bindings;
+ sortedBindings.clear();
+ std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
- return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
+ return a.data()->binding < b.data()->binding;
});
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
for (const QRhiShaderResourceBinding &binding : qAsConst(sortedBindings)) {
- const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
+ const QRhiShaderResourceBinding::Data *b = binding.data();
VkDescriptorSetLayoutBinding vkbinding;
memset(&vkbinding, 0, sizeof(vkbinding));
- vkbinding.binding = b->binding;
+ vkbinding.binding = uint32_t(b->binding);
vkbinding.descriptorType = toVkDescriptorType(b);
vkbinding.descriptorCount = 1; // no array support yet
vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
@@ -5746,6 +5890,9 @@ bool QVkGraphicsPipeline::build()
release();
QRHI_RES_RHI(QRhiVulkan);
+ if (!rhiD->sanityCheckGraphicsPipeline(this))
+ return false;
+
if (!rhiD->ensurePipelineCache())
return false;
@@ -5787,25 +5934,24 @@ bool QVkGraphicsPipeline::build()
shaderStageCreateInfos.append(shaderInfo);
}
}
- pipelineInfo.stageCount = shaderStageCreateInfos.count();
+ pipelineInfo.stageCount = uint32_t(shaderStageCreateInfos.count());
pipelineInfo.pStages = shaderStageCreateInfos.constData();
- const QVector<QRhiVertexInputBinding> bindings = m_vertexInputLayout.bindings();
QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
- for (int i = 0, ie = bindings.count(); i != ie; ++i) {
- const QRhiVertexInputBinding &binding(bindings[i]);
+ int bindingIndex = 0;
+ for (auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
+ it != itEnd; ++it, ++bindingIndex)
+ {
VkVertexInputBindingDescription bindingInfo = {
- uint32_t(i),
- binding.stride(),
- binding.classification() == QRhiVertexInputBinding::PerVertex
+ uint32_t(bindingIndex),
+ it->stride(),
+ it->classification() == QRhiVertexInputBinding::PerVertex
? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
};
- if (binding.classification() == QRhiVertexInputBinding::PerInstance
- && binding.instanceStepRate() != 1)
- {
+ if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
if (rhiD->vertexAttribDivisorAvailable) {
- nonOneStepRates.append({ uint32_t(i), uint32_t(binding.instanceStepRate()) });
+ nonOneStepRates.append({ uint32_t(bindingIndex), uint32_t(it->instanceStepRate()) });
} else {
qWarning("QRhiVulkan: Instance step rates other than 1 not supported without "
"VK_EXT_vertex_attribute_divisor on the device and "
@@ -5814,29 +5960,30 @@ bool QVkGraphicsPipeline::build()
}
vertexBindings.append(bindingInfo);
}
- const QVector<QRhiVertexInputAttribute> attributes = m_vertexInputLayout.attributes();
QVarLengthArray<VkVertexInputAttributeDescription, 4> vertexAttributes;
- for (const QRhiVertexInputAttribute &attribute : attributes) {
+ for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
+ it != itEnd; ++it)
+ {
VkVertexInputAttributeDescription attributeInfo = {
- uint32_t(attribute.location()),
- uint32_t(attribute.binding()),
- toVkAttributeFormat(attribute.format()),
- attribute.offset()
+ uint32_t(it->location()),
+ uint32_t(it->binding()),
+ toVkAttributeFormat(it->format()),
+ it->offset()
};
vertexAttributes.append(attributeInfo);
}
VkPipelineVertexInputStateCreateInfo vertexInputInfo;
memset(&vertexInputInfo, 0, sizeof(vertexInputInfo));
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertexInputInfo.vertexBindingDescriptionCount = vertexBindings.count();
+ vertexInputInfo.vertexBindingDescriptionCount = uint32_t(vertexBindings.count());
vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
- vertexInputInfo.vertexAttributeDescriptionCount = vertexAttributes.count();
+ vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.count());
vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo;
if (!nonOneStepRates.isEmpty()) {
memset(&divisorInfo, 0, sizeof(divisorInfo));
divisorInfo.sType = VkStructureType(1000190001); // VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT
- divisorInfo.vertexBindingDivisorCount = nonOneStepRates.count();
+ divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.count());
divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
vertexInputInfo.pNext = &divisorInfo;
}
@@ -5853,7 +6000,7 @@ bool QVkGraphicsPipeline::build()
VkPipelineDynamicStateCreateInfo dynamicInfo;
memset(&dynamicInfo, 0, sizeof(dynamicInfo));
dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
- dynamicInfo.dynamicStateCount = dynEnable.count();
+ dynamicInfo.dynamicStateCount = uint32_t(dynEnable.count());
dynamicInfo.pDynamicStates = dynEnable.constData();
pipelineInfo.pDynamicState = &dynamicInfo;
@@ -5925,7 +6072,7 @@ bool QVkGraphicsPipeline::build()
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
vktargetBlends.append(blend);
}
- blendInfo.attachmentCount = vktargetBlends.count();
+ blendInfo.attachmentCount = uint32_t(vktargetBlends.count());
blendInfo.pAttachments = vktargetBlends.constData();
pipelineInfo.pColorBlendState = &blendInfo;
@@ -6126,11 +6273,11 @@ QSize QVkSwapChain::surfacePixelSize()
QRHI_RES_RHI(QRhiVulkan);
rhiD->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rhiD->physDev, surface, &surfaceCaps);
VkExtent2D bufferSize = surfaceCaps.currentExtent;
- if (bufferSize.width == quint32(-1)) {
- Q_ASSERT(bufferSize.height == quint32(-1));
+ if (bufferSize.width == uint32_t(-1)) {
+ Q_ASSERT(bufferSize.height == uint32_t(-1));
return m_window->size() * m_window->devicePixelRatio();
}
- return QSize(bufferSize.width, bufferSize.height);
+ return QSize(int(bufferSize.width), int(bufferSize.height));
}
QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
@@ -6198,7 +6345,7 @@ bool QVkSwapChain::ensureSurface()
QRHI_RES_RHI(QRhiVulkan);
if (rhiD->gfxQueueFamilyIdx != -1) {
- if (!rhiD->inst->supportsPresent(rhiD->physDev, rhiD->gfxQueueFamilyIdx, m_window)) {
+ if (!rhiD->inst->supportsPresent(rhiD->physDev, uint32_t(rhiD->gfxQueueFamilyIdx), m_window)) {
qWarning("Presenting not supported on this window");
return false;
}
@@ -6227,7 +6374,7 @@ bool QVkSwapChain::ensureSurface()
rhiD->vkGetPhysicalDeviceSurfaceFormatsKHR(rhiD->physDev, surface, &formatCount, formats.data());
const bool srgbRequested = m_flags.testFlag(sRGB);
- for (quint32 i = 0; i < formatCount; ++i) {
+ for (int i = 0; i < int(formatCount); ++i) {
if (formats[i].format != VK_FORMAT_UNDEFINED && srgbRequested == isSrgbFormat(formats[i].format)) {
colorFormat = formats[i].format;
colorSpace = formats[i].colorSpace;
@@ -6276,9 +6423,16 @@ bool QVkSwapChain::buildOrResize()
m_depthStencil->sampleCount(), m_sampleCount);
}
if (m_depthStencil && m_depthStencil->pixelSize() != pixelSize) {
- qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
- m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
- pixelSize.width(), pixelSize.height());
+ if (m_depthStencil->flags().testFlag(QRhiRenderBuffer::UsedWithSwapChainOnly)) {
+ m_depthStencil->setPixelSize(pixelSize);
+ if (!m_depthStencil->build())
+ qWarning("Failed to rebuild swapchain's associated depth-stencil buffer for size %dx%d",
+ pixelSize.width(), pixelSize.height());
+ } else {
+ qWarning("Depth-stencil buffer's size (%dx%d) does not match the surface size (%dx%d). Expect problems.",
+ m_depthStencil->pixelSize().width(), m_depthStencil->pixelSize().height(),
+ pixelSize.width(), pixelSize.height());
+ }
}
if (!m_renderPassDesc)
@@ -6288,7 +6442,7 @@ bool QVkSwapChain::buildOrResize()
Q_ASSERT(rtWrapper.d.rp && rtWrapper.d.rp->rp);
rtWrapper.d.pixelSize = pixelSize;
- rtWrapper.d.dpr = window->devicePixelRatio();
+ rtWrapper.d.dpr = float(window->devicePixelRatio());
rtWrapper.d.sampleCount = samples;
rtWrapper.d.colorAttCount = 1;
if (m_depthStencil) {
@@ -6315,10 +6469,10 @@ bool QVkSwapChain::buildOrResize()
memset(&fbInfo, 0, sizeof(fbInfo));
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = rtWrapper.d.rp->rp;
- fbInfo.attachmentCount = rtWrapper.d.colorAttCount + rtWrapper.d.dsAttCount + rtWrapper.d.resolveAttCount;
+ fbInfo.attachmentCount = uint32_t(rtWrapper.d.colorAttCount + rtWrapper.d.dsAttCount + rtWrapper.d.resolveAttCount);
fbInfo.pAttachments = views;
- fbInfo.width = pixelSize.width();
- fbInfo.height = pixelSize.height();
+ fbInfo.width = uint32_t(pixelSize.width());
+ fbInfo.height = uint32_t(pixelSize.height());
fbInfo.layers = 1;
VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo, nullptr, &image.fb);
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index 962a1b8eb7..d0e1e6758b 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -79,7 +79,7 @@ struct QVkBuffer : public QRhiBuffer
VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
- QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
+ QVarLengthArray<QRhiResourceUpdateBatchPrivate::BufferOp, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
struct UsageState {
@@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
- QVector<QRhiShaderResourceBinding> sortedBindings;
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int poolIndex = -1;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
@@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
- QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
+ QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
friend class QRhiVulkan;
};
@@ -711,7 +711,9 @@ public:
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
- void makeThreadLocalNativeContextCurrent() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
VkResult createDescriptorPool(VkDescriptorPool *pool);
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);
@@ -730,7 +732,8 @@ public:
VkSampleCountFlagBits samples,
VkFormat colorFormat);
bool createOffscreenRenderPass(VkRenderPass *rp,
- const QVector<QRhiColorAttachment> &colorAttachments,
+ const QRhiColorAttachment *firstColorAttachment,
+ const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
bool preserveDs,
QRhiRenderBuffer *depthStencilBuffer,
@@ -803,6 +806,7 @@ public:
VkDeviceSize ubufAlign;
VkDeviceSize texbufAlign;
bool hasWideLines = false;
+ bool deviceLost = false;
bool debugMarkersAvailable = false;
bool vertexAttribDivisorAvailable = false;
@@ -849,17 +853,25 @@ public:
VkFence cmdFence = VK_NULL_HANDLE;
} ofr;
- struct ActiveReadback {
+ struct TextureReadback {
int activeFrameSlot = -1;
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
- VkBuffer buf;
- QVkAlloc bufAlloc;
- quint32 bufSize;
+ VkBuffer stagingBuf;
+ QVkAlloc stagingAlloc;
+ quint32 byteSize;
QSize pixelSize;
QRhiTexture::Format format;
};
- QVector<ActiveReadback> activeReadbacks;
+ QVector<TextureReadback> activeTextureReadbacks;
+ struct BufferReadback {
+ int activeFrameSlot = -1;
+ QRhiBufferReadbackResult *result;
+ int byteSize;
+ VkBuffer stagingBuf;
+ QVkAlloc stagingAlloc;
+ };
+ QVector<BufferReadback> activeBufferReadbacks;
struct DeferredReleaseEntry {
enum Type {
@@ -929,7 +941,8 @@ public:
Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiVulkan::ActiveReadback, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 72ce53c87a..6a2c596557 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -450,7 +450,7 @@ QShaderKey::QShaderKey(QShader::Source s,
}
/*!
- Returns \c true if the two QShader objects \a a and \a b are equal,
+ Returns \c true if the two QShader objects \a lhs and \a rhs are equal,
meaning they are for the same stage with matching sets of shader source or
binary code.
@@ -486,7 +486,7 @@ uint qHash(const QShader &s, uint seed) Q_DECL_NOTHROW
}
/*!
- Returns \c true if the two QShaderVersion objects \a a and \a b are
+ Returns \c true if the two QShaderVersion objects \a lhs and \a rhs are
equal.
\relates QShaderVersion
@@ -506,7 +506,7 @@ bool operator==(const QShaderVersion &lhs, const QShaderVersion &rhs) Q_DECL_NOT
*/
/*!
- Returns \c true if the two QShaderKey objects \a a and \a b are equal.
+ Returns \c true if the two QShaderKey objects \a lhs and \a rhs are equal.
\relates QShaderKey
*/
@@ -536,7 +536,7 @@ uint qHash(const QShaderKey &k, uint seed) Q_DECL_NOTHROW
}
/*!
- Returns \c true if the two QShaderCode objects \a a and \a b are equal.
+ Returns \c true if the two QShaderCode objects \a lhs and \a rhs are equal.
\relates QShaderCode
*/
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp
index c38a83c497..179d5f3a07 100644
--- a/src/gui/rhi/qshaderdescription.cpp
+++ b/src/gui/rhi/qshaderdescription.cpp
@@ -1022,7 +1022,7 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
return;
}
- Q_ASSERT(ref.load() == 1); // must be detached
+ Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
inVars.clear();
outVars.clear();
diff --git a/src/gui/rhi/tdr.hlsl b/src/gui/rhi/tdr.hlsl
new file mode 100644
index 0000000000..f79de91c4a
--- /dev/null
+++ b/src/gui/rhi/tdr.hlsl
@@ -0,0 +1,9 @@
+RWBuffer<uint> uav;
+cbuffer ConstantBuffer { uint zero; }
+
+[numthreads(256, 1, 1)]
+void killDeviceByTimingOut(uint3 id: SV_DispatchThreadID)
+{
+ while (zero == 0)
+ uav[id.x] = zero;
+}
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
index 5263ece87c..8b8f3e28ac 100644
--- a/src/gui/text/qabstracttextdocumentlayout.cpp
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -660,7 +660,7 @@ QTextBlock QAbstractTextDocumentLayout::blockWithMarkerAt(const QPointF &pos) co
{
QTextBlock block = document()->firstBlock();
while (block.isValid()) {
- if (block.blockFormat().marker() != QTextBlockFormat::NoMarker) {
+ if (block.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker) {
QRectF blockBr = blockBoundingRect(block);
QTextBlockFormat blockFmt = block.blockFormat();
QFontMetrics fm(block.charFormat().font());
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 3c1a052f37..76fde5388c 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -2096,10 +2096,11 @@ uint qHash(const QFont &font, uint seed) noexcept
*/
bool QFont::fromString(const QString &descrip)
{
- const auto l = descrip.splitRef(QLatin1Char(','));
-
- int count = l.count();
- if (!count || (count > 2 && count < 9) || count > 11) {
+ const QStringRef sr = QStringRef(&descrip).trimmed();
+ const auto l = sr.split(QLatin1Char(','));
+ const int count = l.count();
+ if (!count || (count > 2 && count < 9) || count > 11 ||
+ l.first().isEmpty()) {
qWarning("QFont::fromString: Invalid description '%s'",
descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
return false;
@@ -3175,8 +3176,7 @@ QDebug operator<<(QDebug stream, const QFont &font)
QDebug debug(&fontDescription);
debug.nospace();
- QFontPrivate priv;
- const QFont defaultFont(&priv);
+ const QFont defaultFont(new QFontPrivate);
for (int property = QFont::FamilyResolved; property < QFont::AllPropertiesResolved; property <<= 1) {
const bool resolved = (font.resolve_mask & property) != 0;
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index ce6bb0c347..261e1d831b 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -2684,7 +2684,7 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
QtFontDesc desc;
QList<int> blackListed;
int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
- if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases()) {
+ if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
// We populated familiy aliases (e.g. localized families), so try again
index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
}
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index 80b092f177..63e6b48e4f 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -49,7 +49,6 @@ QT_BEGIN_NAMESPACE
class QStringList;
-template <class T> class QList;
struct QFontDef;
class QFontEngine;
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index 38ba7f10b2..f79c5db625 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -104,7 +104,7 @@ class Q_GUI_EXPORT QPlatformFontDatabase
public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
- virtual bool populateFamilyAliases() { return false; }
+ virtual bool populateFamilyAliases(const QString &missingFamily) { Q_UNUSED(missingFamily); return false; }
virtual void populateFamily(const QString &familyName);
virtual void invalidate();
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index c80617f929..22c249d604 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -1970,9 +1970,12 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
QRectF body = QRectF(QPointF(0, 0), d->pageSize);
QPointF pageNumberPos;
+ qreal sourceDpiX = qt_defaultDpiX();
+ qreal sourceDpiY = qt_defaultDpiY();
+ const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
+ const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
+
if (documentPaginated) {
- qreal sourceDpiX = qt_defaultDpi();
- qreal sourceDpiY = sourceDpiX;
QPaintDevice *dev = doc->documentLayout()->paintDevice();
if (dev) {
@@ -1980,9 +1983,6 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
sourceDpiY = dev->logicalDpiY();
}
- const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
- const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
-
// scale to dpi
p.scale(dpiScaleX, dpiScaleY);
@@ -2011,15 +2011,21 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
// copy the custom object handlers
layout->d_func()->handlers = documentLayout()->d_func()->handlers;
- int dpiy = p.device()->logicalDpiY();
- int margin = (int) ((2/2.54)*dpiy); // 2 cm margins
+ // 2 cm margins, scaled to device in QTextDocumentLayoutPrivate::layoutFrame
+ const int horizontalMargin = int((2/2.54)*sourceDpiX);
+ const int verticalMargin = int((2/2.54)*sourceDpiY);
QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
- fmt.setMargin(margin);
+ fmt.setLeftMargin(horizontalMargin);
+ fmt.setRightMargin(horizontalMargin);
+ fmt.setTopMargin(verticalMargin);
+ fmt.setBottomMargin(verticalMargin);
doc->rootFrame()->setFrameFormat(fmt);
+ // pageNumberPos must be in device coordinates, so scale to device here
+ const int dpiy = p.device()->logicalDpiY();
body = QRectF(0, 0, printer->width(), printer->height());
- pageNumberPos = QPointF(body.width() - margin,
- body.height() - margin
+ pageNumberPos = QPointF(body.width() - horizontalMargin * dpiScaleX,
+ body.height() - verticalMargin * dpiScaleY
+ QFontMetrics(doc->defaultFont(), p.device()).ascent()
+ 5 * dpiy / 72.0);
clonedDoc->setPageSize(body.size());
@@ -2067,8 +2073,9 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
\enum QTextDocument::ResourceType
This enum describes the types of resources that can be loaded by
- QTextDocument's loadResource() function.
+ QTextDocument's loadResource() function or by QTextBrowser::setSource().
+ \value UnknownResource No resource is loaded, or the resource type is not known.
\value HtmlResource The resource contains HTML.
\value ImageResource The resource contains image data.
Currently supported data types are QVariant::Pixmap and
@@ -2082,7 +2089,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
\value UserResource The first available value for user defined
resource types.
- \sa loadResource()
+ \sa loadResource(), QTextBrowser::sourceType()
*/
/*!
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index 723e5c907c..742c56382d 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -1062,6 +1062,7 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
fmt.setLeftPadding(leftPadding(currentNodeIdx));
if (rightPadding(currentNodeIdx) >= 0)
fmt.setRightPadding(rightPadding(currentNodeIdx));
+#ifndef QT_NO_CSSPARSER
if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0)
fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge));
if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0)
@@ -1086,6 +1087,7 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge));
if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush)
fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge));
+#endif
cell.setFormat(fmt);
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index b02723c047..7be114adf9 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -265,6 +265,9 @@ public:
inline QFixed topPadding(QTextTable *table, const QTextTableCell &cell) const
{
+#ifdef QT_NO_CSSPARSER
+ Q_UNUSED(table);
+#endif
return paddingProperty(cell.format(), QTextFormat::TableCellTopPadding)
#ifndef QT_NO_CSSPARSER
+ cellBorderWidth(table, cell, QCss::TopEdge)
@@ -274,6 +277,9 @@ public:
inline QFixed bottomPadding(QTextTable *table, const QTextTableCell &cell) const
{
+#ifdef QT_NO_CSSPARSER
+ Q_UNUSED(table);
+#endif
return paddingProperty(cell.format(), QTextFormat::TableCellBottomPadding)
#ifndef QT_NO_CSSPARSER
+ cellBorderWidth(table, cell, QCss::BottomEdge)
@@ -283,6 +289,9 @@ public:
inline QFixed leftPadding(QTextTable *table, const QTextTableCell &cell) const
{
+#ifdef QT_NO_CSSPARSER
+ Q_UNUSED(table);
+#endif
return paddingProperty(cell.format(), QTextFormat::TableCellLeftPadding)
#ifndef QT_NO_CSSPARSER
+ cellBorderWidth(table, cell, QCss::LeftEdge)
@@ -292,6 +301,9 @@ public:
inline QFixed rightPadding(QTextTable *table, const QTextTableCell &cell) const
{
+#ifdef QT_NO_CSSPARSER
+ Q_UNUSED(table);
+#endif
return paddingProperty(cell.format(), QTextFormat::TableCellRightPadding)
#ifndef QT_NO_CSSPARSER
+ cellBorderWidth(table, cell, QCss::RightEdge)
@@ -1034,15 +1046,22 @@ static bool cellClipTest(QTextTable *table, QTextTableData *td,
const QTextTableCell &cell,
QRectF cellRect)
{
+#ifdef QT_NO_CSSPARSER
+ Q_UNUSED(table);
+ Q_UNUSED(cell);
+#endif
+
if (!cell_context.clip.isValid())
return false;
if (td->borderCollapse) {
// we need to account for the cell borders in the clipping test
+#ifndef QT_NO_CSSPARSER
cellRect.adjust(-axisEdgeData(table, td, cell, QCss::LeftEdge).width / 2,
-axisEdgeData(table, td, cell, QCss::TopEdge).width / 2,
axisEdgeData(table, td, cell, QCss::RightEdge).width / 2,
axisEdgeData(table, td, cell, QCss::BottomEdge).width / 2);
+#endif
} else {
qreal border = td->border.toReal();
cellRect.adjust(-border, -border, border, border);
@@ -1798,6 +1817,13 @@ void QTextDocumentLayoutPrivate::drawTableCellBorder(const QRectF &cellRect, QPa
if (turn_off_antialiasing)
painter->setRenderHint(QPainter::Antialiasing, false);
+#else
+ Q_UNUSED(cell);
+ Q_UNUSED(cellRect);
+ Q_UNUSED(painter);
+ Q_UNUSED(table);
+ Q_UNUSED(td);
+ Q_UNUSED(cell);
#endif
}
@@ -2168,11 +2194,11 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
QBrush brush = context.palette.brush(QPalette::Text);
- bool marker = bl.blockFormat().marker() != QTextBlockFormat::NoMarker;
+ bool marker = bl.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker;
if (marker) {
int adj = fontMetrics.lineSpacing() / 6;
r.adjust(-adj, 0, -adj, 0);
- if (bl.blockFormat().marker() == QTextBlockFormat::Checked) {
+ if (bl.blockFormat().marker() == QTextBlockFormat::MarkerType::Checked) {
// ### Qt6: render with QStyle / PE_IndicatorCheckBox. We don't currently
// have access to that here, because it would be a widget dependency.
painter->setPen(QPen(painter->pen().color(), 2));
@@ -2285,12 +2311,14 @@ QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QT
+ td->border
+ td->paddingProperty(cell.format(), QTextFormat::TableCellTopPadding); // top cell-border is not repeated
+#ifndef QT_NO_CSSPARSER
const int headerRowCount = t->format().headerRowCount();
if (td->borderCollapse && headerRowCount > 0) {
// consider the header row's bottom edge width
qreal headerRowBottomBorderWidth = axisEdgeData(t, td, t->cellAt(headerRowCount - 1, cell.column()), QCss::BottomEdge).width;
layoutStruct.pageTopMargin += QFixed::fromReal(scaleToDevice(headerRowBottomBorderWidth) / 2);
}
+#endif
layoutStruct.pageBottomMargin = td->effectiveBottomMargin + td->cellSpacing + td->effectiveBottomBorder + td->bottomPadding(t, cell);
layoutStruct.pageBottom = (currentPage + 1) * layoutStruct.pageHeight - layoutStruct.pageBottomMargin;
@@ -2915,24 +2943,24 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in
{
QTextFrameFormat fformat = f->frameFormat();
// set sizes of this frame from the format
- QFixed tm = QFixed::fromReal(fformat.topMargin());
+ QFixed tm = QFixed::fromReal(scaleToDevice(fformat.topMargin())).round();
if (tm != fd->topMargin) {
fd->topMargin = tm;
fullLayout = true;
}
- QFixed bm = QFixed::fromReal(fformat.bottomMargin());
+ QFixed bm = QFixed::fromReal(scaleToDevice(fformat.bottomMargin())).round();
if (bm != fd->bottomMargin) {
fd->bottomMargin = bm;
fullLayout = true;
}
- fd->leftMargin = QFixed::fromReal(fformat.leftMargin());
- fd->rightMargin = QFixed::fromReal(fformat.rightMargin());
- QFixed b = QFixed::fromReal(fformat.border());
+ fd->leftMargin = QFixed::fromReal(scaleToDevice(fformat.leftMargin())).round();
+ fd->rightMargin = QFixed::fromReal(scaleToDevice(fformat.rightMargin())).round();
+ QFixed b = QFixed::fromReal(scaleToDevice(fformat.border())).round();
if (b != fd->border) {
fd->border = b;
fullLayout = true;
}
- QFixed p = QFixed::fromReal(fformat.padding());
+ QFixed p = QFixed::fromReal(scaleToDevice(fformat.padding())).round();
if (p != fd->padding) {
fd->padding = p;
fullLayout = true;
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index c267ade0c2..b37353bf2c 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -399,6 +399,7 @@ struct QBidiAlgorithm {
analysis[i].bidiDirection = (level & 1) ? QChar::DirR : QChar::DirL;
runHasContent = true;
lastRunWithContent = -1;
+ ++isolatePairPosition;
}
int runBeforeIsolate = runs.size();
ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.top().level + 2) & ~1);
@@ -440,21 +441,19 @@ struct QBidiAlgorithm {
doEmbed(true, true, false);
break;
case QChar::DirLRI:
- Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
doEmbed(false, false, true);
- ++isolatePairPosition;
break;
case QChar::DirRLI:
- Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
doEmbed(true, false, true);
- ++isolatePairPosition;
break;
case QChar::DirFSI: {
- const auto &pair = isolatePairs.at(isolatePairPosition);
- Q_ASSERT(pair.start == i);
- bool isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
+ bool isRtl = false;
+ if (isolatePairPosition < isolatePairs.size()) {
+ const auto &pair = isolatePairs.at(isolatePairPosition);
+ Q_ASSERT(pair.start == i);
+ isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
+ }
doEmbed(isRtl, false, true);
- ++isolatePairPosition;
break;
}
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 47a38db3ad..e3bd49a15e 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -650,6 +650,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value TableColumns
\value TableColumnWidthConstraints
\value TableHeaderRowCount
+ \value TableBorderCollapse Specifies the \l QTextTableFormat::borderCollapse property.
Table cell properties
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index 12f14a1555..28da0fe344 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -627,7 +627,7 @@ public:
LineDistanceHeight = 4
};
- enum MarkerType {
+ enum class MarkerType {
NoMarker = 0,
Unchecked = 1,
Checked = 2
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index b96263f5fc..fe7e422923 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -190,8 +190,8 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
m_listItem = true;
MD_BLOCK_LI_DETAIL *detail = static_cast<MD_BLOCK_LI_DETAIL *>(det);
m_markerType = detail->is_task ?
- (detail->task_mark == ' ' ? QTextBlockFormat::Unchecked : QTextBlockFormat::Checked) :
- QTextBlockFormat::NoMarker;
+ (detail->task_mark == ' ' ? QTextBlockFormat::MarkerType::Unchecked : QTextBlockFormat::MarkerType::Checked) :
+ QTextBlockFormat::MarkerType::NoMarker;
qCDebug(lcMD) << "LI";
} break;
case MD_BLOCK_UL: {
@@ -549,7 +549,7 @@ void QTextMarkdownImporter::insertBlock()
blockFormat.setTopMargin(m_paragraphMargin);
blockFormat.setBottomMargin(m_paragraphMargin);
}
- if (m_markerType == QTextBlockFormat::NoMarker)
+ if (m_markerType == QTextBlockFormat::MarkerType::NoMarker)
blockFormat.clearProperty(QTextFormat::BlockMarker);
else
blockFormat.setMarker(m_markerType);
diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h
index 1b8c2ca354..35655aff8a 100644
--- a/src/gui/text/qtextmarkdownimporter_p.h
+++ b/src/gui/text/qtextmarkdownimporter_p.h
@@ -128,7 +128,7 @@ private:
Features m_features;
QTextImageFormat m_imageFormat;
QTextListFormat m_listFormat;
- QTextBlockFormat::MarkerType m_markerType = QTextBlockFormat::NoMarker;
+ QTextBlockFormat::MarkerType m_markerType = QTextBlockFormat::MarkerType::NoMarker;
bool m_needsInsertBlock = false;
bool m_needsInsertList = false;
bool m_listItem = false; // true from the beginning of LI to the end of the first P
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index cbfb092485..764c64aead 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -327,10 +327,10 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
break;
}
switch (blockFmt.marker()) {
- case QTextBlockFormat::Checked:
+ case QTextBlockFormat::MarkerType::Checked:
bullet += " [x]";
break;
- case QTextBlockFormat::Unchecked:
+ case QTextBlockFormat::MarkerType::Unchecked:
bullet += " [ ]";
break;
default:
diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp
index 3561c185a6..0e8666565f 100644
--- a/src/gui/text/qtextodfwriter.cpp
+++ b/src/gui/text/qtextodfwriter.cpp
@@ -358,7 +358,7 @@ void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &bloc
int precedingSpaces = 0;
int exportedIndex = 0;
for (int i=0; i <= fragmentText.count(); ++i) {
- QChar character = fragmentText[i];
+ QChar character = (i == fragmentText.count() ? QChar() : fragmentText.at(i));
bool isSpace = character.unicode() == ' ';
// find more than one space. -> <text:s text:c="2" />
diff --git a/src/gui/text/qtextoption.h b/src/gui/text/qtextoption.h
index 8b57278633..a90d73dc43 100644
--- a/src/gui/text/qtextoption.h
+++ b/src/gui/text/qtextoption.h
@@ -48,8 +48,6 @@
QT_BEGIN_NAMESPACE
-
-template <typename T> class QList;
struct QTextOptionPrivate;
class Q_GUI_EXPORT QTextOption
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..daf37e3dc8 100644
--- a/src/gui/vulkan/qvulkaninstance.cpp
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -775,6 +775,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 6d12377a60..790bef9e14 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -498,12 +498,12 @@ QVector<int> QVulkanWindow::supportedSampleCounts()
VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
- for (size_t i = 0; i < sizeof(qvk_sampleCounts) / sizeof(qvk_sampleCounts[0]); ++i) {
- if ((color & qvk_sampleCounts[i].mask)
- && (depth & qvk_sampleCounts[i].mask)
- && (stencil & qvk_sampleCounts[i].mask))
+ for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ if ((color & qvk_sampleCount.mask)
+ && (depth & qvk_sampleCount.mask)
+ && (stencil & qvk_sampleCount.mask))
{
- result.append(qvk_sampleCounts[i].count);
+ result.append(qvk_sampleCount.count);
}
}
@@ -547,9 +547,9 @@ void QVulkanWindow::setSampleCount(int sampleCount)
return;
}
- for (size_t i = 0; i < sizeof(qvk_sampleCounts) / sizeof(qvk_sampleCounts[0]); ++i) {
- if (qvk_sampleCounts[i].count == sampleCount) {
- d->sampleCount = qvk_sampleCounts[i].mask;
+ for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ if (qvk_sampleCount.count == sampleCount) {
+ d->sampleCount = qvk_sampleCount.mask;
return;
}
}
@@ -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..777be237a8 100644
--- a/src/gui/vulkan/qvulkanwindow_p.h
+++ b/src/gui/vulkan/qvulkanwindow_p.h
@@ -102,6 +102,7 @@ public:
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;