RHI: facilitate compressed atlas textures in gles2 backend

Since glCompressedTexImage2D() does not allow zero data, it could not
be executed during texture build. Instead it would be done during the
first subresource upload. This made atlasing clumsy, since one had to
introduce a fake upload of the full texture size before the subtexture
uploads. This commits lets the gles2 backend deal with that instead.

Introduces the UsedAsCompressedAtlas QRhiTexture::Flag for opting in
to this behavior.

Task-number: QTBUG-78582
Change-Id: Ib6e4ea637c62cc8a51bd9a4a06e59882f335f2a7
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Eirik Aavitsland 2020-05-15 09:20:08 +02:00
parent 3ec0df4b5f
commit 880f709fd0
4 changed files with 29 additions and 5 deletions

View File

@ -1496,9 +1496,6 @@ QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRh
the size of the source image() must match the subresource. When providing
raw data instead, sufficient number of bytes must be provided in data().
\note With compressed textures the first upload must always match the
subresource size due to graphics API limitations with some backends.
sourceTopLeft() is supported only for QImage-based uploads, and specifies
the top-left corner of the source rectangle.
@ -2197,6 +2194,9 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const
\value UsedWithLoadStore The texture is going to be used with image
load/store operations, for example, in a compute shader.
\value UsedAsCompressedAtlas The texture has a compressed format and the
dimensions of subresource uploads may not match the texture size.
*/
/*!

View File

@ -727,7 +727,8 @@ public:
sRGB = 1 << 4,
UsedAsTransferSource = 1 << 5,
UsedWithGenerateMips = 1 << 6,
UsedWithLoadStore = 1 << 7
UsedWithLoadStore = 1 << 7,
UsedAsCompressedAtlas = 1 << 8
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@ -1505,9 +1505,29 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.args.subImage.data = cbD->retainImage(img);
cbD->commands.append(cmd);
} else if (!rawData.isEmpty() && isCompressed) {
if (!texD->compressedAtlasBuilt && (texD->flags() & QRhiTexture::UsedAsCompressedAtlas)) {
// Build on first upload since glCompressedTexImage2D cannot take nullptr data
quint32 byteSize = 0;
compressedFormatInfo(texD->m_format, texD->m_pixelSize, nullptr, &byteSize, nullptr);
QByteArray zeroBuf(byteSize, 0);
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::CompressedImage;
cmd.args.compressedImage.target = texD->target;
cmd.args.compressedImage.texture = texD->texture;
cmd.args.compressedImage.faceTarget = faceTargetBase + uint(layer);
cmd.args.compressedImage.level = level;
cmd.args.compressedImage.glintformat = texD->glintformat;
cmd.args.compressedImage.w = texD->m_pixelSize.width();
cmd.args.compressedImage.h = texD->m_pixelSize.height();
cmd.args.compressedImage.size = byteSize;
cmd.args.compressedImage.data = cbD->retainData(zeroBuf);
cbD->commands.append(cmd);
texD->compressedAtlasBuilt = true;
}
const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
: subresDesc.sourceSize();
if (texD->specified) {
if (texD->specified || texD->compressedAtlasBuilt) {
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::CompressedSubImage;
cmd.args.compressedSubImage.target = texD->target;
@ -3666,6 +3686,7 @@ void QGles2Texture::release()
texture = 0;
specified = false;
compressedAtlasBuilt = false;
QRHI_RES_RHI(QRhiGles2);
if (owns)
@ -3785,6 +3806,7 @@ bool QGles2Texture::buildFrom(QRhiTexture::NativeTexture src)
texture = textureId;
specified = true;
compressedAtlasBuilt = true;
QRHI_RES_RHI(QRhiGles2);
QRHI_PROF;

View File

@ -148,6 +148,7 @@ struct QGles2Texture : public QRhiTexture
GLenum gltype;
QGles2SamplerData samplerState;
bool specified = false;
bool compressedAtlasBuilt = false;
int mipLevelCount = 0;
enum Access {