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.7 6.6 6.5
Change-Id: Ic0f1617d4699217a7549c13e916be96108183d03
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
bb10
Artem Dyomin 2024-02-05 15:27:25 +01:00
parent 1d799e9108
commit 1d6bb23f62
1 changed files with 30 additions and 37 deletions

View File

@ -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);
}