From 07059d4d1d167b21fb83b27f85af3668f6587146 Mon Sep 17 00:00:00 2001 From: Artem Dyomin Date: Mon, 5 Feb 2024 15:27:25 +0100 Subject: [PATCH] Fix loading QRhiTexture from image on gles The code should consider that image may be created by a pointer to user data, with original alignments. It means that we the way of setting parameters from raw data and QImage should be the same. In Qt Multimedia we want to pass a zero-copy image to rhi creation to get rid of an extra copy: codereview.qt-project.org/c/qt/qtmultimedia/+/537062 Aslo, data align has been fixed. Due to the documentation, GL_UNPACK_ALIGNMENT can be 8, 4, 2, 1. Let's find the biggest possible align. Task-number: QTBUG-121934 Pick-to: 6.6 6.5 Change-Id: Ic0f1617d4699217a7549c13e916be96108183d03 Reviewed-by: Laszlo Agocs (cherry picked from commit 1d6bb23f6285252f7fa6cac87003cbe0f33f51af) Reviewed-by: Qt Cherry-pick Bot --- src/gui/rhi/qrhigles2.cpp | 67 ++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index e41ac6d353b..2f0659909f1 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -2287,17 +2287,15 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb const GLenum effectiveTarget = faceTargetBase + (isCubeMap ? uint(layer) : 0u); const QPoint dp = subresDesc.destinationTopLeft(); const QByteArray rawData = subresDesc.data(); - if (!subresDesc.image().isNull()) { - QImage img = subresDesc.image(); - QSize size = img.size(); + + auto setCmdByNotCompressedData = [&](const void* data, QSize size, quint32 dataStride) + { + quint32 bytesPerLine = 0; + quint32 bytesPerPixel = 0; + textureFormatInfo(texD->m_format, size, &bytesPerLine, nullptr, &bytesPerPixel); + QGles2CommandBuffer::Command &cmd(cbD->commands.get()); cmd.cmd = QGles2CommandBuffer::Command::SubImage; - if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) { - const QPoint sp = subresDesc.sourceTopLeft(); - if (!subresDesc.sourceSize().isEmpty()) - size = subresDesc.sourceSize(); - img = img.copy(sp.x(), sp.y(), size.width(), size.height()); - } cmd.args.subImage.target = texD->target; cmd.args.subImage.texture = texD->texture; cmd.args.subImage.faceTarget = effectiveTarget; @@ -2309,9 +2307,27 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb cmd.args.subImage.h = size.height(); cmd.args.subImage.glformat = texD->glformat; cmd.args.subImage.gltype = texD->gltype; - cmd.args.subImage.rowStartAlign = 4; - cmd.args.subImage.rowLength = 0; - cmd.args.subImage.data = cbD->retainImage(img); + + if (dataStride == 0) + dataStride = bytesPerLine; + + cmd.args.subImage.rowStartAlign = (dataStride & 3) ? 1 : 4; + cmd.args.subImage.rowLength = bytesPerPixel ? dataStride / bytesPerPixel : 0; + + cmd.args.subImage.data = data; + }; + + if (!subresDesc.image().isNull()) { + QImage img = subresDesc.image(); + QSize size = img.size(); + if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) { + const QPoint sp = subresDesc.sourceTopLeft(); + if (!subresDesc.sourceSize().isEmpty()) + size = subresDesc.sourceSize(); + img = img.copy(sp.x(), sp.y(), size.width(), size.height()); + } + + setCmdByNotCompressedData(cbD->retainImage(img), size, img.bytesPerLine()); } else if (!rawData.isEmpty() && isCompressed) { const int depth = qMax(1, texD->m_depth); const int arraySize = qMax(0, texD->m_arraySize); @@ -2379,31 +2395,8 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb } else if (!rawData.isEmpty()) { const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize) : subresDesc.sourceSize(); - quint32 bytesPerLine = 0; - quint32 bytesPerPixel = 0; - textureFormatInfo(texD->m_format, size, &bytesPerLine, nullptr, &bytesPerPixel); - QGles2CommandBuffer::Command &cmd(cbD->commands.get()); - cmd.cmd = QGles2CommandBuffer::Command::SubImage; - cmd.args.subImage.target = texD->target; - cmd.args.subImage.texture = texD->texture; - cmd.args.subImage.faceTarget = effectiveTarget; - cmd.args.subImage.level = level; - cmd.args.subImage.dx = dp.x(); - cmd.args.subImage.dy = is1D && isArray ? layer : dp.y(); - cmd.args.subImage.dz = is3D || isArray ? layer : 0; - cmd.args.subImage.w = size.width(); - cmd.args.subImage.h = size.height(); - cmd.args.subImage.glformat = texD->glformat; - cmd.args.subImage.gltype = texD->gltype; - // Default unpack alignment (row start alignment - // requirement) is 4. QImage guarantees 4 byte aligned - // row starts, but our raw data here does not. - cmd.args.subImage.rowStartAlign = (bytesPerLine & 3) ? 1 : 4; - if (subresDesc.dataStride() && bytesPerPixel) - cmd.args.subImage.rowLength = subresDesc.dataStride() / bytesPerPixel; - else - cmd.args.subImage.rowLength = 0; - cmd.args.subImage.data = cbD->retainData(rawData); + + setCmdByNotCompressedData(cbD->retainData(rawData), size, subresDesc.dataStride()); } else { qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level); }