29Manager::Manager(QSGDefaultRenderContext *rc,
const QSize &surfacePixelSize, QSurface *maybeSurface)
33 const int maxSize = m_rhi->resourceLimit(QRhi::TextureSizeMax);
37 const int widthHint = qMax(1, surfacePixelSize.width());
38 const int heightHint = qMax(1, surfacePixelSize.height());
39 int w = qMin(maxSize, qt_sg_envInt(
"QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(widthHint - 1))));
40 int h = qMin(maxSize, qt_sg_envInt(
"QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(heightHint - 1))));
42 if (maybeSurface && maybeSurface->surfaceClass() == QSurface::Window) {
43 QWindow *window =
static_cast<QWindow *>(maybeSurface);
45 if ((window->type() & Qt::CoverWindow) == Qt::CoverWindow) {
51 m_atlas_size_limit = qt_sg_envInt(
"QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
52 m_atlas_size = QSize(w, h);
54 qCDebug(QSG_LOG_INFO,
"rhi texture atlas dimensions: %dx%d", w, h);
97 QSGTexture *t =
nullptr;
98 if (!qsgEnableCompressedAtlas() || !factory->textureData()->isValid())
101 unsigned int format = factory->textureData()->glInternalFormat();
102 QSGCompressedTexture::FormatInfo fmt = QSGCompressedTexture::formatInfo(format);
103 if (!m_rhi->isTextureFormatSupported(fmt.rhiFormat))
106 QSize size = factory->textureData()->size();
107 if (size.width() < m_atlas_size_limit && size.height() < m_atlas_size_limit) {
108 QHash<
unsigned int, QSGCompressedAtlasTexture::Atlas*>::const_iterator i = m_atlases.constFind(format);
109 if (i == m_atlases.cend()) {
110 auto newAtlas =
new QSGCompressedAtlasTexture::Atlas(m_rc, m_atlas_size, format);
111 i = m_atlases.insert(format, newAtlas);
113 const QTextureFileData *cmpData = factory->textureData();
114 t = i.value()->create(cmpData->getDataView(), size);
220 Texture *tex =
static_cast<Texture *>(t);
221 const QRect &r = tex->atlasSubRect();
222 QImage image = tex->image();
227 if (m_format == QRhiTexture::BGRA8) {
228 if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied)
229 image =
std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
230 }
else if (image.format() != QImage::Format_RGBA8888_Premultiplied) {
231 image =
std::move(image).convertToFormat(QImage::Format_RGBA8888_Premultiplied);
234 if (m_debug_overlay) {
236 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
237 p.fillRect(0, 0, image.width(), image.height(), QBrush(QColor::fromRgbF(0, 1, 1, 0.5)));
240 const int iw = image.width();
241 const int ih = image.height();
242 const int bpl = image.bytesPerLine() / 4;
243 QVarLengthArray<quint32, 1024> tmpBits(qMax(iw + 2, ih + 2));
244 const int tmpBitsSize = tmpBits.size() * 4;
245 const quint32 *src =
reinterpret_cast<
const quint32 *>(image.constBits());
246 quint32 *dst = tmpBits.data();
247 QVarLengthArray<QRhiTextureUploadEntry, 5> entries;
251 memcpy(dst + 1, src, iw *
sizeof(quint32));
252 dst[1 + iw] = src[iw - 1];
255 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y()));
256 subresDesc.setSourceSize(QSize(iw + 2, 1));
257 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
261 const quint32 *lastRow = src + bpl * (ih - 1);
263 memcpy(dst + 1, lastRow, iw *
sizeof(quint32));
264 dst[1 + iw] = lastRow[iw - 1];
267 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + ih + 1));
268 subresDesc.setSourceSize(QSize(iw + 2, 1));
269 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
273 for (
int i = 0; i < ih; ++i)
274 dst[i] = src[i * bpl];
277 subresDesc.setDestinationTopLeft(QPoint(r.x(), r.y() + 1));
278 subresDesc.setSourceSize(QSize(1, ih));
279 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
284 for (
int i = 0; i < ih; ++i)
285 dst[i] = src[i * bpl + iw - 1];
288 subresDesc.setDestinationTopLeft(QPoint(r.x() + iw + 1, r.y() + 1));
289 subresDesc.setSourceSize(QSize(1, ih));
290 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
296 int ey = sy + r.height() - 2;
297 entries.reserve(4 + (ey - sy));
298 for (
int y = sy; y < ey; ++y) {
300 subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, y));
301 subresDesc.setSourceSize(QSize(r.width() - 2, 1));
302 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
307 subresDesc.setDestinationTopLeft(QPoint(r.x() + 1, r.y() + 1));
308 subresDesc.setSourceSize(QSize(r.width() - 2, r.height() - 2));
309 entries.append(QRhiTextureUploadEntry(0, 0, subresDesc));
313 desc.setEntries(entries.cbegin(), entries.cend());
314 resourceUpdates->uploadTexture(m_texture, desc);
316 const QSize textureSize = t->textureSize();
317 if (textureSize.width() > m_atlas_transient_image_threshold || textureSize.height() > m_atlas_transient_image_threshold)
320 qCDebug(QSG_LOG_TIME_TEXTURE,
"atlastexture upload enqueued in: %lldms (%dx%d)",
321 qsg_renderer_timer.elapsed(),
322 t->textureSize().width(),
323 t->textureSize().height());
387 if (!m_nonatlas_texture) {
388 m_nonatlas_texture =
new QSGPlainTexture;
389 if (!m_image.isNull()) {
390 m_nonatlas_texture->setImage(m_image);
391 m_nonatlas_texture->setFiltering(filtering());
393 QSGDefaultRenderContext *rc = m_atlas->renderContext();
394 QRhi *rhi = m_atlas->rhi();
395 Q_ASSERT(rhi->isRecordingFrame());
396 const QRect r = atlasSubRectWithoutPadding();
398 QRhiTexture *extractTex = rhi->newTexture(m_atlas->texture()->format(), r.size());
399 if (extractTex->create()) {
400 bool ownResUpd =
false;
401 QRhiResourceUpdateBatch *resUpd = resourceUpdates;
404 resUpd = rhi->nextResourceUpdateBatch();
407 desc.setSourceTopLeft(r.topLeft());
408 desc.setPixelSize(r.size());
409 resUpd->copyTexture(extractTex, m_atlas->texture(), desc);
411 rc->currentFrameCommandBuffer()->resourceUpdate(resUpd);
414 m_nonatlas_texture->setTexture(extractTex);
415 m_nonatlas_texture->setOwnsTexture(
true);
416 m_nonatlas_texture->setHasAlphaChannel(m_has_alpha);
417 m_nonatlas_texture->setTextureSize(r.size());
421 m_nonatlas_texture->setMipmapFiltering(mipmapFiltering());
422 m_nonatlas_texture->setFiltering(filtering());
423 return m_nonatlas_texture;
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
void enqueueTextureUpload(TextureBase *t, QRhiResourceUpdateBatch *resourceUpdates) override
QSGTexture * create(const QImage &image, bool hasAlphaChannel)
qint64 comparisonKey() const override
Returns a key suitable for comparing textures.
void commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch *resourceUpdates) override
Call this function to enqueue image upload operations to resourceUpdates, in case there are any pendi...
bool hasAlphaChannel() const override
Returns true if the texture data contains an alpha channel.
QSGTexture * removedFromAtlas(QRhiResourceUpdateBatch *resourceUpdates) const override
This function returns a copy of the current texture which is removed from its atlas.