Commit ab819490 authored by Laszlo Agocs's avatar Laszlo Agocs

Drop public data members and inner structs in Tex.UploadDesc.

parent b04ccdb2
......@@ -177,13 +177,13 @@ void Window::customRender()
u->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
}
if (!d.compressedData.isEmpty()) {
QRhiTextureUploadDescription desc;
QRhiTextureUploadDescription::Layer layer;
QVector<QRhiTextureMipLevel> mipImages;
for (int i = 0; i < d.compressedData.count(); ++i) {
QRhiTextureUploadDescription::Layer::MipLevel image(d.compressedData[i]);
layer.mipImages.append(image);
QRhiTextureMipLevel image(d.compressedData[i]);
mipImages.append(image);
}
desc.layers.append(layer);
QRhiTextureLayer layer(mipImages);
QRhiTextureUploadDescription desc({ layer });
u->uploadTexture(d.tex, desc);
d.compressedData.clear();
}
......
......@@ -182,27 +182,23 @@ void Window::customRender()
}
if (!d.compressedData.isEmpty()) {
{
QRhiTextureUploadDescription desc;
QRhiTextureUploadDescription::Layer layer;
QRhiTextureUploadDescription::Layer::MipLevel image(d.compressedData[0]);
layer.mipImages.append(image);
desc.layers.append(layer);
QRhiTextureMipLevel image(d.compressedData[0]);
QRhiTextureLayer layer({ image });
QRhiTextureUploadDescription desc({ layer });
u->uploadTexture(d.tex, desc);
d.compressedData.clear();
}
// now exercise uploading a smaller compressed image into the same texture
{
QRhiTextureUploadDescription desc;
QRhiTextureUploadDescription::Layer layer;
QRhiTextureUploadDescription::Layer::MipLevel image(d.compressedData2[0]);
QRhiTextureMipLevel image(d.compressedData2[0]);
// positions and sizes must be multiples of 4 here (for BC1)
image.destinationTopLeft = QPoint(16, 32);
image.setDestinationTopLeft(QPoint(16, 32));
// the image is smaller than the subresource size (224x64 vs
// 256x256) so the size must be specified manually
image.sourceSize = QSize(224, 64);
layer.mipImages.append(image);
desc.layers.append(layer);
image.setSourceSize(QSize(224, 64));
QRhiTextureLayer layer({ image });
QRhiTextureUploadDescription desc({ layer });
u->uploadTexture(d.tex, desc);
d.compressedData2.clear();
}
......
......@@ -82,14 +82,15 @@ void Window::customInit()
QRhiTextureUploadDescription desc;
QImage img = QImage(":/c.png").mirrored().convertToFormat(QImage::Format_RGBA8888); // just use the same image for all faces for now
auto texLayer = QRhiTextureUploadDescription::Layer({ QRhiTextureUploadDescription::Layer::MipLevel(img) });
desc.layers
<< texLayer // +X
<< texLayer // -X
<< texLayer // +Y
<< texLayer // -Y
<< texLayer // +Z
<< texLayer; // -Z
QRhiTextureLayer texLayer({ { img } });
desc.setLayers({
texLayer, // +X
texLayer, // -X
texLayer, // +Y
texLayer, // -Y
texLayer, // +Z
texLayer // -Z
});
d.initialUpdates->uploadTexture(d.tex, desc);
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
......
......@@ -184,17 +184,12 @@ void Window::customRender()
// Partially change the texture.
if (d.testStage == 1) {
QRhiTextureUploadDescription desc;
QRhiTextureUploadDescription::Layer layer;
QRhiTextureUploadDescription::Layer::MipLevel mipDesc;
mipDesc.image = d.customImage;
QRhiTextureMipLevel mipDesc(d.customImage);
// The image here is smaller than the original. Use a non-zero position
// to make it more interesting.
mipDesc.destinationTopLeft = QPoint(100, 20);
layer.mipImages.append(mipDesc);
desc.layers.append(layer);
mipDesc.setDestinationTopLeft(QPoint(100, 20));
QRhiTextureLayer layer({ mipDesc });
QRhiTextureUploadDescription desc({ layer });
u->uploadTexture(d.tex, desc);
}
......@@ -235,17 +230,12 @@ void Window::customRender()
// Now again upload customImage but this time only a part of it.
if (d.testStage == 5) {
QRhiTextureUploadDescription desc;
QRhiTextureUploadDescription::Layer layer;
QRhiTextureUploadDescription::Layer::MipLevel mipDesc;
mipDesc.image = d.customImage;
mipDesc.destinationTopLeft = QPoint(10, 120);
mipDesc.sourceSize = QSize(50, 40);
mipDesc.sourceTopLeft = QPoint(20, 10);
layer.mipImages.append(mipDesc);
desc.layers.append(layer);
QRhiTextureMipLevel mipDesc(d.customImage);
mipDesc.setDestinationTopLeft(QPoint(10, 120));
mipDesc.setSourceSize(QSize(50, 40));
mipDesc.setSourceTopLeft(QPoint(20, 10));
QRhiTextureLayer layer({ mipDesc });
QRhiTextureUploadDescription desc({ layer });
u->uploadTexture(d.newTex, desc);
}
......
......@@ -193,17 +193,19 @@ void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourc
if (!m_image.isNull()) {
if (MIPMAP) {
QRhiTextureUploadDescription desc;
desc.layers.append(QRhiTextureUploadDescription::Layer());
QRhiTextureLayer layer;
if (!AUTOGENMIPMAP) {
// the ghetto mipmap generator...
QVector<QRhiTextureMipLevel> mipImages;
for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) {
QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size()));
desc.layers[0].mipImages.push_back({ image });
mipImages.append({ image });
}
layer.setMipImages(mipImages);
} else {
desc.layers[0].mipImages.push_back({ m_image });
layer.setMipImages({ { m_image } });
}
QRhiTextureUploadDescription desc({ layer });
resourceUpdates->uploadTexture(m_tex, desc);
if (AUTOGENMIPMAP)
resourceUpdates->generateMips(m_tex);
......
......@@ -634,13 +634,13 @@ QT_BEGIN_NAMESPACE
*/
/*!
\class QRhiTextureUploadDescription::Layer
\class QRhiTextureLayer
\inmodule QtRhi
\brief Describes one layer (face for cubemaps) in a texture upload operation.
*/
/*!
\class QRhiTextureUploadDescription::Layer::MipLevel
\class QRhiTextureMipLevel
\inmodule QtRhi
\brief Describes one mip level in a layer in a texture upload operation.
......@@ -648,23 +648,23 @@ QT_BEGIN_NAMESPACE
former is only allowed for uncompressed textures, while the latter is only
supported for compressed ones.
\note \l image and \l compressedData cannot be both set.
\note image() and compressedData() cannot be both set at the same time.
\l destinationTopLeft specifies the top-left corner of the target
destinationTopLeft() specifies the top-left corner of the target
rectangle. Defaults to (0, 0).
An empty \l sourceSize (the default) indicates that size is assumed to be
An empty sourceSize() (the default) indicates that size is assumed to be
the size of the subresource. For uncompressed textures this implies that
the size of the source \l image must match the subresource. For compressed
textures sufficient amount of data must be provided in \l compressedData.
the size of the source image() must match the subresource. For compressed
textures sufficient amount of data must be provided in compressedData().
\note With compressed textures the first upload must always match the
subresource size due to graphics API limitations with some backends.
\l sourceTopLeft is is only supported for uncompressed textures, and
sourceTopLeft() is is only supported for uncompressed textures, and
specifies the top-left corner of the source rectangle.
\note Setting \l sourceSize or \l sourceTopLeft may trigger a QImage copy
\note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
internally, depending on the format and the backend.
*/
......
......@@ -365,34 +365,66 @@ private:
Q_DECLARE_TYPEINFO(QRhiTextureRenderTargetDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiTextureUploadDescription
class Q_RHI_EXPORT QRhiTextureMipLevel
{
struct Q_RHI_EXPORT Layer {
struct Q_RHI_EXPORT MipLevel {
MipLevel() { }
MipLevel(const QImage &image_) : image(image_) { }
MipLevel(const QByteArray &compressedData_) : compressedData(compressedData_) { }
QImage image;
QByteArray compressedData;
QPoint destinationTopLeft;
QSize sourceSize;
QPoint sourceTopLeft;
};
Layer() { }
Layer(const QVector<MipLevel> &mipImages_) : mipImages(mipImages_) { }
QVector<MipLevel> mipImages;
};
public:
QRhiTextureMipLevel() { }
QRhiTextureMipLevel(const QImage &image) : m_image(image) { }
QRhiTextureMipLevel(const QByteArray &compressedData) : m_compressedData(compressedData) { }
QImage image() const { return m_image; }
void setImage(const QImage &image) { m_image = image; }
QByteArray compressedData() const { return m_compressedData; }
void setCompressedData(const QByteArray &data) { m_compressedData = data; }
QPoint destinationTopLeft() const { return m_destinationTopLeft; }
void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; }
QSize sourceSize() const { return m_sourceSize; }
void setSourceSize(const QSize &size) { m_sourceSize = size; }
QPoint sourceTopLeft() const { return m_sourceTopLeft; }
void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; }
private:
QImage m_image;
QByteArray m_compressedData;
QPoint m_destinationTopLeft;
QSize m_sourceSize;
QPoint m_sourceTopLeft;
};
Q_DECLARE_TYPEINFO(QRhiTextureMipLevel, Q_MOVABLE_TYPE);
class Q_RHI_EXPORT QRhiTextureLayer
{
public:
QRhiTextureLayer() { }
QRhiTextureLayer(const QVector<QRhiTextureMipLevel> &mipImages) : m_mipImages(mipImages) { }
QVector<QRhiTextureMipLevel> mipImages() const { return m_mipImages; }
void setMipImages(const QVector<QRhiTextureMipLevel> &images) { m_mipImages = images; }
private:
QVector<QRhiTextureMipLevel> m_mipImages;
};
Q_DECLARE_TYPEINFO(QRhiTextureLayer, Q_MOVABLE_TYPE);
class Q_RHI_EXPORT QRhiTextureUploadDescription
{
public:
QRhiTextureUploadDescription() { }
QRhiTextureUploadDescription(const QVector<Layer> &layers_) : layers(layers_) { }
QVector<Layer> layers;
QRhiTextureUploadDescription(const QVector<QRhiTextureLayer> &layers) : m_layers(layers) { }
QVector<QRhiTextureLayer> layers() const { return m_layers; }
void setLayers(const QVector<QRhiTextureLayer> &layers) { m_layers = layers; }
private:
QVector<QRhiTextureLayer> m_layers;
};
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription::Layer::MipLevel, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription::Layer, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiTextureCopyDescription
......
......@@ -932,13 +932,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
for (const QRhiResourceUpdateBatchPrivate::TextureUpload &u : ud->textureUploads) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.tex);
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
const QVector<QRhiTextureLayer> layers = u.desc.layers();
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
UINT subres = D3D11CalcSubresource(level, layer, texD->mipLevelCount);
const int dx = mipDesc.destinationTopLeft.x();
const int dy = mipDesc.destinationTopLeft.y();
const QPoint dp = mipDesc.destinationTopLeft();
D3D11_BOX box;
box.front = 0;
// back, right, bottom are exclusive
......@@ -948,58 +949,53 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.updateSubRes.dst = texD->tex;
cmd.args.updateSubRes.dstSubRes = subres;
if (!mipDesc.image.isNull()) {
QImage img = mipDesc.image;
int w = img.width();
int h = img.height();
if (!mipDesc.image().isNull()) {
QImage img = mipDesc.image();
QSize size = img.size();
int bpl = img.bytesPerLine();
if (!mipDesc.sourceSize.isEmpty() || !mipDesc.sourceTopLeft.isNull()) {
const int sx = mipDesc.sourceTopLeft.x();
const int sy = mipDesc.sourceTopLeft.y();
if (!mipDesc.sourceSize.isEmpty()) {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
}
if (!mipDesc.sourceSize().isEmpty() || !mipDesc.sourceTopLeft().isNull()) {
const QPoint sp = mipDesc.sourceTopLeft();
if (!mipDesc.sourceSize().isEmpty())
size = mipDesc.sourceSize();
if (img.depth() == 32) {
const int offset = sy * img.bytesPerLine() + sx * 4;
const int offset = sp.y() * img.bytesPerLine() + sp.x() * 4;
cmd.args.updateSubRes.src = cbD->retainImage(img) + offset;
} else {
img = img.copy(sx, sy, w, h);
img = img.copy(sp.x(), sp.y(), size.width(), size.height());
bpl = img.bytesPerLine();
cmd.args.updateSubRes.src = cbD->retainImage(img);
}
} else {
cmd.args.updateSubRes.src = cbD->retainImage(img);
}
box.left = dx;
box.top = dy;
box.right = dx + w;
box.bottom = dy + h;
box.left = dp.x();
box.top = dp.y();
box.right = dp.x() + size.width();
box.bottom = dp.y() + size.height();
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.srcRowPitch = bpl;
} else if (!mipDesc.compressedData.isEmpty() && isCompressedFormat(texD->m_format)) {
int w, h;
if (mipDesc.sourceSize.isEmpty()) {
w = qFloor(float(qMax(1, texD->m_pixelSize.width() >> level)));
h = qFloor(float(qMax(1, texD->m_pixelSize.height() >> level)));
} else if (!mipDesc.compressedData().isEmpty() && isCompressedFormat(texD->m_format)) {
QSize size;
if (mipDesc.sourceSize().isEmpty()) {
size.setWidth(qFloor(float(qMax(1, texD->m_pixelSize.width() >> level))));
size.setHeight(qFloor(float(qMax(1, texD->m_pixelSize.height() >> level))));
} else {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
size = mipDesc.sourceSize();
}
quint32 bpl = 0;
QSize blockDim;
compressedFormatInfo(texD->m_format, QSize(w, h), &bpl, nullptr, &blockDim);
compressedFormatInfo(texD->m_format, size, &bpl, nullptr, &blockDim);
// 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(dx, blockDim.width());
box.top = aligned(dy, blockDim.height());
box.right = aligned(dx + w, blockDim.width());
box.bottom = aligned(dy + h, blockDim.height());
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());
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.src = cbD->retainData(mipDesc.compressedData);
cmd.args.updateSubRes.src = cbD->retainData(mipDesc.compressedData());
cmd.args.updateSubRes.srcRowPitch = bpl;
}
cbD->commands.append(cmd);
......
......@@ -708,20 +708,21 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
const bool isCompressed = isCompressedFormat(texD->m_format);
const bool isCubeMap = texD->m_flags.testFlag(QRhiTexture::CubeMap);
const GLenum faceTargetBase = isCubeMap ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
const int dx = mipDesc.destinationTopLeft.x();
const int dy = mipDesc.destinationTopLeft.y();
if (isCompressed && !mipDesc.compressedData.isEmpty()) {
int w, h;
if (mipDesc.sourceSize.isEmpty()) {
w = qFloor(float(qMax(1, texD->m_pixelSize.width() >> level)));
h = qFloor(float(qMax(1, texD->m_pixelSize.height() >> level)));
const QVector<QRhiTextureLayer> layers = u.desc.layers();
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
const QPoint dp = mipDesc.destinationTopLeft();
const QByteArray compressedData = mipDesc.compressedData();
if (isCompressed && !compressedData.isEmpty()) {
QSize size;
if (mipDesc.sourceSize().isEmpty()) {
size.setWidth(qFloor(float(qMax(1, texD->m_pixelSize.width() >> level))));
size.setHeight(qFloor(float(qMax(1, texD->m_pixelSize.height() >> level))));
} else {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
size = mipDesc.sourceSize();
}
if (texD->specified) {
QGles2CommandBuffer::Command cmd;
......@@ -729,13 +730,13 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.compressedSubImage.dst = texD;
cmd.args.compressedSubImage.faceTarget = faceTargetBase + layer;
cmd.args.compressedSubImage.level = level;
cmd.args.compressedSubImage.dx = dx;
cmd.args.compressedSubImage.dy = dy;
cmd.args.compressedSubImage.w = w;
cmd.args.compressedSubImage.h = h;
cmd.args.compressedSubImage.dx = dp.x();
cmd.args.compressedSubImage.dy = dp.y();
cmd.args.compressedSubImage.w = size.width();
cmd.args.compressedSubImage.h = size.height();
cmd.args.compressedSubImage.glintformat = texD->glintformat;
cmd.args.compressedSubImage.size = mipDesc.compressedData.size();
cmd.args.compressedSubImage.data = cbD->retainData(mipDesc.compressedData);
cmd.args.compressedSubImage.size = compressedData.size();
cmd.args.compressedSubImage.data = cbD->retainData(compressedData);
cbD->commands.append(cmd);
} else {
QGles2CommandBuffer::Command cmd;
......@@ -744,34 +745,30 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.compressedImage.faceTarget = faceTargetBase + layer;
cmd.args.compressedImage.level = level;
cmd.args.compressedImage.glintformat = texD->glintformat;
cmd.args.compressedImage.w = w;
cmd.args.compressedImage.h = h;
cmd.args.compressedImage.size = mipDesc.compressedData.size();
cmd.args.compressedImage.data = cbD->retainData(mipDesc.compressedData);
cmd.args.compressedImage.w = size.width();
cmd.args.compressedImage.h = size.height();
cmd.args.compressedImage.size = compressedData.size();
cmd.args.compressedImage.data = cbD->retainData(compressedData);
cbD->commands.append(cmd);
}
} else {
QImage img = mipDesc.image;
int w = img.width();
int h = img.height();
QImage img = mipDesc.image();
QSize size = img.size();
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::SubImage;
if (!mipDesc.sourceSize.isEmpty() || !mipDesc.sourceTopLeft.isNull()) {
const int sx = mipDesc.sourceTopLeft.x();
const int sy = mipDesc.sourceTopLeft.y();
if (!mipDesc.sourceSize.isEmpty()) {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
}
img = img.copy(sx, sy, w, h);
if (!mipDesc.sourceSize().isEmpty() || !mipDesc.sourceTopLeft().isNull()) {
const QPoint sp = mipDesc.sourceTopLeft();
if (!mipDesc.sourceSize().isEmpty())
size = mipDesc.sourceSize();
img = img.copy(sp.x(), sp.y(), size.width(), size.height());
}
cmd.args.subImage.dst = texD;
cmd.args.subImage.faceTarget = faceTargetBase + layer;
cmd.args.subImage.level = level;
cmd.args.subImage.dx = dx;
cmd.args.subImage.dy = dy;
cmd.args.subImage.w = w;
cmd.args.subImage.h = h;
cmd.args.subImage.dx = dp.x();
cmd.args.subImage.dy = dp.y();
cmd.args.subImage.w = size.width();
cmd.args.subImage.h = size.height();
cmd.args.subImage.glformat = texD->glformat;
cmd.args.subImage.gltype = texD->gltype;
cmd.args.subImage.data = cbD->retainImage(img);
......
......@@ -1098,18 +1098,20 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
};
for (const QRhiResourceUpdateBatchPrivate::TextureUpload &u : ud->textureUploads) {
if (u.desc.layers.isEmpty() || u.desc.layers[0].mipImages.isEmpty())
const QVector<QRhiTextureLayer> layers = u.desc.layers();
if (layers.isEmpty() || layers[0].mipImages.isEmpty())
continue;
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.tex);
qsizetype stagingSize = 0;
const int texbufAlign = 256; // probably not needed
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
Q_ASSERT(layerDesc.mipImages.count() == 1 || utexD->m_flags.testFlag(QRhiTexture::MipMapped));
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
Q_ASSERT(mipImages.count() == 1 || utexD->m_flags.testFlag(QRhiTexture::MipMapped));
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
const qsizetype imageSizeBytes = mipDesc.image.isNull() ?
mipDesc.compressedData.size() : mipDesc.image.sizeInBytes();
if (imageSizeBytes > 0)
......@@ -1125,27 +1127,28 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
void *mp = [utexD->d->stagingBuf[currentFrameSlot] contents];
qsizetype curOfs = 0;
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
int dx = mipDesc.destinationTopLeft.x();
int dy = mipDesc.destinationTopLeft.y();
if (!mipDesc.image.isNull()) {
const qsizetype fullImageSizeBytes = mipDesc.image.sizeInBytes();
QImage img = mipDesc.image;
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
const QPoint dp = mipDesc.destinationTopLeft();
const QByteArray compressedData = mipDesc.compressedData();
QImage img = mipDesc.image();
if (!img.isNull()) {
const qsizetype fullImageSizeBytes = img.sizeInBytes();
int w = img.width();
int h = img.height();
int bpl = img.bytesPerLine();
int srcOffset = 0;
if (!mipDesc.sourceSize.isEmpty() || !mipDesc.sourceTopLeft.isNull()) {
const int sx = mipDesc.sourceTopLeft.x();
const int sy = mipDesc.sourceTopLeft.y();
if (!mipDesc.sourceSize.isEmpty()) {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
if (!mipDesc.sourceSize().isEmpty() || !mipDesc.sourceTopLeft().isNull()) {
const int sx = mipDesc.sourceTopLeft().x();
const int sy = mipDesc.sourceTopLeft().y();
if (!mipDesc.sourceSize().isEmpty()) {
w = mipDesc.sourceSize().width();
h = mipDesc.sourceSize().height();
}
if (img.depth() == 32) {
memcpy(reinterpret_cast<char *>(mp) + curOfs, img.constBits(), fullImageSizeBytes);
......@@ -1169,34 +1172,34 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
toTexture: utexD->d->tex
destinationSlice: layer
destinationLevel: level
destinationOrigin: MTLOriginMake(dx, dy, 0)
destinationOrigin: MTLOriginMake(dp.x(), dp.y(), 0)
options: MTLBlitOptionNone];
curOfs += aligned(fullImageSizeBytes, texbufAlign);
} else if (!mipDesc.compressedData.isEmpty() && isCompressedFormat(utexD->m_format)) {
} else if (!compressedData.isEmpty() && isCompressedFormat(utexD->m_format)) {
const int subresw = qFloor(float(qMax(1, utexD->m_pixelSize.width() >> level)));
const int subresh = qFloor(float(qMax(1, utexD->m_pixelSize.height() >> level)));
int w, h;
if (mipDesc.sourceSize.isEmpty()) {
if (mipDesc.sourceSize().isEmpty()) {
w = subresw;
h = subresh;
} else {
w = mipDesc.sourceSize.width();
h = mipDesc.sourceSize.height();
w = mipDesc.sourceSize().width();
h = mipDesc.sourceSize().height();
}
quint32 bpl = 0;
QSize blockDim;
compressedFormatInfo(utexD->m_format, QSize(w, h), &bpl, nullptr, &blockDim);
dx = aligned(dx, blockDim.width());
dy = aligned(dy, blockDim.height());
const int dx = aligned(dp.x(), blockDim.width());
const int dy = aligned(dp.y(), blockDim.height());
if (dx + w != subresw)
w = aligned(w, blockDim.width());
if (dy + h != subresh)
h = aligned(h, blockDim.height());
memcpy(reinterpret_cast<char *>(mp) + curOfs, mipDesc.compressedData.constData(), mipDesc.compressedData.size());
memcpy(reinterpret_cast<char *>(mp) + curOfs, compressedData.constData(), compressedData.size());
[blitEnc copyFromBuffer: utexD->d->stagingBuf[currentFrameSlot]
sourceOffset: curOfs
......@@ -1209,7 +1212,7 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
destinationOrigin: MTLOriginMake(dx, dy, 0)
options: MTLBlitOptionNone];
curOfs += aligned(mipDesc.compressedData.size(), texbufAlign);
curOfs += aligned(compressedData.size(), texbufAlign);
}
}
}
......
......@@ -2236,19 +2236,21 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
}
for (const QRhiResourceUpdateBatchPrivate::TextureUpload &u : ud->textureUploads) {
if (u.desc.layers.isEmpty() || u.desc.layers[0].mipImages.isEmpty())
const QVector<QRhiTextureLayer> layers = u.desc.layers();
if (layers.isEmpty() || layers[0].mipImages().isEmpty())
continue;
QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex);
VkDeviceSize stagingSize = 0;
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
Q_ASSERT(layerDesc.mipImages.count() == 1 || utexD->m_flags.testFlag(QRhiTexture::MipMapped));
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
const qsizetype imageSizeBytes = mipDesc.image.isNull() ?
mipDesc.compressedData.size() : mipDesc.image.sizeInBytes();
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
Q_ASSERT(mipImages.count() == 1 || utexD->m_flags.testFlag(QRhiTexture::MipMapped));
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
const qsizetype imageSizeBytes = mipDesc.image().isNull() ?
mipDesc.compressedData().size() : mipDesc.image().sizeInBytes();
if (imageSizeBytes > 0)
stagingSize += aligned(imageSizeBytes, texbufAlign);
}
......@@ -2286,10 +2288,11 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
continue;
}
QVector<QImage> tempImages; // yes, we rely heavily on implicit sharing in QImage
for (int layer = 0, layerCount = u.desc.layers.count(); layer != layerCount; ++layer) {
const QRhiTextureUploadDescription::Layer &layerDesc(u.desc.layers[layer]);
for (int level = 0, levelCount = layerDesc.mipImages.count(); level != levelCount; ++level) {
const QRhiTextureUploadDescription::Layer::MipLevel mipDesc(layerDesc.mipImages[level]);
for (int layer = 0, layerCount = layers.count(); layer != layerCount; ++layer) {
const QRhiTextureLayer &layerDesc(layers[layer]);
const QVector<QRhiTextureMipLevel> mipImages = layerDesc.mipImages();
for (int level = 0, levelCount = mipImages.count(); level != levelCount; ++level) {
const QRhiTextureMipLevel &mipDesc(mipImages[level]);
qsizetype imageSizeBytes = 0;
const void *src = nullptr;
VkBufferImageCopy copyInfo;
......@@ -2301,62 +2304,57 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
copyInfo.imageSubresource.layerCount = 1;
copyInfo.imageExtent.depth = 1;
const int dx = mipDesc.destinationTopLeft.x();
const int dy = mipDesc.destinationTopLeft.y();
if (!mipDesc.image.isNull()) {
imageSizeBytes = mipDesc.image.sizeInBytes();
const QPoint dp = mipDesc.destinationTopLeft();
const QImage image = mipDesc.image();
const QByteArray compressedData = mipDesc.compressedData();
if (!image.isNull()) {
imageSizeBytes = image.sizeInBytes();
if (imageSizeBytes > 0) {
QImage img = mipDesc.image;
int w = img.width();
int h = img.height();
QImage img = image;
QSize size = img.size();
src = img.constBits();
copyInfo.bufferRowLength = w; // this is in pixels, not bytes